xbe.at

Machine learning / Model evaluation and validation

Response:

11 min read, 18 sections

Contents
  1. Response:
  2. Why Accuracy Can Be Misleading in Machine Learning
  3. The Class Imbalance Problem
  4. Real-Life Example: Medical Diagnosis
  5. Precision and Recall
  6. F1 Score: Balancing Precision and Recall
  7. ROC Curve and AUC
  8. Confusion Matrix Visualization
  9. Cross-Validation: Assessing Model Stability
  10. Stratified Sampling for Imbalanced Datasets
  11. Real-Life Example: Spam Detection
  12. Handling Class Imbalance: Oversampling and Undersampling
  13. Learning Curves: Diagnosing Bias and Variance
  14. Response:
  15. Learning Curves: Diagnosing Bias and Variance
  16. Feature Importance: Understanding Model Decisions
  17. Ensemble Methods: Combining Models for Better Performance
  18. Additional Resources

undefined

Response:

Why Accuracy Can Be Misleading in Machine Learning

Accuracy is often used as a primary metric for evaluating machine learning models. However, relying solely on accuracy can lead to incorrect conclusions about a model's performance, especially in certain scenarios. This presentation will explore why accuracy can be misleading and introduce alternative metrics and techniques to better evaluate model performance.

Copyimport numpy as np
from sklearn.metrics import accuracy_score

# Example of a misleading accuracy score
y_true = np.array([0, 0, 0, 0, 1, 1, 1, 1, 1, 1])
y_pred = np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0])

accuracy = accuracy_score(y_true, y_pred)
print(f"Accuracy: {accuracy}")  # Output: Accuracy: 0.4

# Despite 40% accuracy, the model always predicts class 0

The Class Imbalance Problem

Class imbalance occurs when one class in a dataset significantly outnumbers the other(s). In such cases, accuracy can be misleading as a model that always predicts the majority class will have high accuracy but fail to identify the minority class.

Copyimport numpy as np
from sklearn.dummy import DummyClassifier
from sklearn.metrics import accuracy_score, confusion_matrix

# Create an imbalanced dataset
X = np.random.rand(1000, 10)
y = np.zeros(1000)
y[:50] = 1  # Only 5% of the data belongs to class 1

# Train a dummy classifier that always predicts the majority class
dummy_clf = DummyClassifier(strategy="most_frequent")
dummy_clf.fit(X, y)

# Make predictions
y_pred = dummy_clf.predict(X)

# Calculate accuracy
accuracy = accuracy_score(y, y_pred)
print(f"Accuracy: {accuracy}")  # Output: Accuracy: 0.95

# Display confusion matrix
print("Confusion Matrix:")
print(confusion_matrix(y, y_pred))

Real-Life Example: Medical Diagnosis

Consider a rare disease affecting 1% of the population. A model that always predicts "no disease" would have 99% accuracy but fail to identify any actual cases.

Copyimport numpy as np
from sklearn.metrics import accuracy_score, confusion_matrix, classification_report

# Simulating a population of 10,000 people
population_size = 10000
disease_prevalence = 0.01

# Generate true labels
y_true = np.random.choice([0, 1], size=population_size, p=[1-disease_prevalence, disease_prevalence])

# Model always predicting "no disease"
y_pred = np.zeros(population_size)

# Calculate metrics
accuracy = accuracy_score(y_true, y_pred)
conf_matrix = confusion_matrix(y_true, y_pred)

print(f"Accuracy: {accuracy:.2f}")
print("\nConfusion Matrix:")
print(conf_matrix)
print("\nClassification Report:")
print(classification_report(y_true, y_pred))

Precision and Recall

To address the limitations of accuracy, we introduce precision and recall. Precision measures the proportion of correct positive predictions, while recall measures the proportion of actual positives correctly identified.

Copyfrom sklearn.metrics import precision_score, recall_score

# Using the medical diagnosis example from the previous slide
precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)

print(f"Precision: {precision:.2f}")
print(f"Recall: {recall:.2f}")

# Interpreting the results
print("\nInterpretation:")
print("Precision of 0.00 means no true positives were predicted.")
print("Recall of 0.00 means no actual positive cases were identified.")

F1 Score: Balancing Precision and Recall

The F1 score is the harmonic mean of precision and recall, providing a single metric that balances both. It's particularly useful when you have an uneven class distribution.

Copyfrom sklearn.metrics import f1_score

# Calculate F1 score
f1 = f1_score(y_true, y_pred)

print(f"F1 Score: {f1:.2f}")

# Demonstrate how F1 score changes with different precision-recall trade-offs
precisions = [0.5, 0.8, 0.9]
recalls = [0.8, 0.5, 0.1]

for p, r in zip(precisions, recalls):
    f1 = 2 * (p * r) / (p + r)
    print(f"Precision: {p:.2f}, Recall: {r:.2f}, F1 Score: {f1:.2f}")

ROC Curve and AUC

The Receiver Operating Characteristic (ROC) curve and Area Under the Curve (AUC) provide a comprehensive view of a model's performance across different classification thresholds.

Copyimport numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import roc_curve, auc
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LogisticRegression

# Generate a synthetic dataset
X, y = make_classification(n_samples=1000, n_classes=2, weights=[0.9, 0.1], random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Train a logistic regression model
model = LogisticRegression()
model.fit(X_train, y_train)

# Get predicted probabilities
y_pred_proba = model.predict_proba(X_test)[:, 1]

# Calculate ROC curve and AUC
fpr, tpr, _ = roc_curve(y_test, y_pred_proba)
roc_auc = auc(fpr, tpr)

# Plot ROC curve
plt.figure()
plt.plot(fpr, tpr, color='darkorange', lw=2, label=f'ROC curve (AUC = {roc_auc:.2f})')
plt.plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver Operating Characteristic (ROC) Curve')
plt.legend(loc="lower right")
plt.show()

Confusion Matrix Visualization

A confusion matrix provides a detailed breakdown of correct and incorrect classifications for each class. Visualizing it can offer insights into model performance.

Copyimport numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.metrics import confusion_matrix

# Generate sample predictions
y_true = np.array([0, 0, 0, 1, 1, 1, 1, 1])
y_pred = np.array([0, 1, 0, 1, 0, 1, 0, 1])

# Create confusion matrix
cm = confusion_matrix(y_true, y_pred)

# Visualize confusion matrix
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion Matrix')
plt.show()

# Print classification metrics
tn, fp, fn, tp = cm.ravel()
accuracy = (tp + tn) / (tp + tn + fp + fn)
precision = tp / (tp + fp)
recall = tp / (tp + fn)
f1 = 2 * (precision * recall) / (precision + recall)

print(f"Accuracy: {accuracy:.2f}")
print(f"Precision: {precision:.2f}")
print(f"Recall: {recall:.2f}")
print(f"F1 Score: {f1:.2f}")

Cross-Validation: Assessing Model Stability

Cross-validation helps assess how well a model generalizes to unseen data by splitting the dataset into multiple training and testing sets.

Copyfrom sklearn.model_selection import cross_val_score
from sklearn.datasets import make_classification
from sklearn.svm import SVC

# Generate a synthetic dataset
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)

# Create an SVM classifier
svm = SVC(kernel='rbf', random_state=42)

# Perform 5-fold cross-validation
cv_scores = cross_val_score(svm, X, y, cv=5)

print("Cross-validation scores:", cv_scores)
print(f"Mean CV Score: {cv_scores.mean():.3f} (+/- {cv_scores.std() * 2:.3f})")

# Visualize cross-validation results
plt.figure(figsize=(8, 6))
plt.boxplot(cv_scores)
plt.title('5-Fold Cross-Validation Results')
plt.ylabel('Accuracy')
plt.show()

Stratified Sampling for Imbalanced Datasets

Stratified sampling ensures that the proportion of samples for each class is roughly the same in train and test sets, which is crucial for imbalanced datasets.

Copyfrom sklearn.model_selection import train_test_split
from collections import Counter

# Create an imbalanced dataset
X = np.random.rand(1000, 5)
y = np.zeros(1000)
y[:100] = 1  # Only 10% of the data belongs to class 1

# Perform stratified split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, stratify=y, random_state=42)

# Check class distribution
print("Original dataset class distribution:")
print(Counter(y))

print("\nTraining set class distribution:")
print(Counter(y_train))

print("\nTest set class distribution:")
print(Counter(y_test))

# Visualize class distribution
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(15, 5))

ax1.pie(Counter(y).values(), labels=Counter(y).keys(), autopct='%1.1f%%')
ax1.set_title('Original Dataset')

ax2.pie(Counter(y_train).values(), labels=Counter(y_train).keys(), autopct='%1.1f%%')
ax2.set_title('Training Set')

ax3.pie(Counter(y_test).values(), labels=Counter(y_test).keys(), autopct='%1.1f%%')
ax3.set_title('Test Set')

plt.tight_layout()
plt.show()

Real-Life Example: Spam Detection

In spam detection, accuracy alone can be misleading. A model that classifies all emails as non-spam might have high accuracy but fail to detect actual spam.

Copyimport numpy as np
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score

# Simulating an email dataset (0: non-spam, 1: spam)
emails = 10000
spam_ratio = 0.2

y_true = np.random.choice([0, 1], size=emails, p=[1-spam_ratio, spam_ratio])

# Model A: Always predicts non-spam
y_pred_A = np.zeros(emails)

# Model B: More balanced predictions
y_pred_B = np.random.choice([0, 1], size=emails, p=[0.85, 0.15])

def evaluate_model(y_true, y_pred, model_name):
    accuracy = accuracy_score(y_true, y_pred)
    precision = precision_score(y_true, y_pred)
    recall = recall_score(y_true, y_pred)
    f1 = f1_score(y_true, y_pred)
    
    print(f"{model_name} Performance:")
    print(f"Accuracy: {accuracy:.3f}")
    print(f"Precision: {precision:.3f}")
    print(f"Recall: {recall:.3f}")
    print(f"F1 Score: {f1:.3f}\n")

evaluate_model(y_true, y_pred_A, "Model A (Always Non-Spam)")
evaluate_model(y_true, y_pred_B, "Model B (Balanced)")

Handling Class Imbalance: Oversampling and Undersampling

When dealing with imbalanced datasets, techniques like oversampling the minority class or undersampling the majority class can help improve model performance.

Copyfrom sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from imblearn.over_sampling import SMOTE
from imblearn.under_sampling import RandomUnderSampler
from sklearn.svm import SVC

# Generate imbalanced dataset
X, y = make_classification(n_samples=10000, n_classes=2, weights=[0.9, 0.1], random_state=42)

# Split the data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Train SVM on imbalanced data
svm = SVC()
svm.fit(X_train, y_train)
y_pred = svm.predict(X_test)
print("Original imbalanced dataset:")
print(classification_report(y_test, y_pred))

# Apply SMOTE (oversampling)
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)

svm_smote = SVC()
svm_smote.fit(X_train_smote, y_train_smote)
y_pred_smote = svm_smote.predict(X_test)
print("\nAfter SMOTE oversampling:")
print(classification_report(y_test, y_pred_smote))

# Apply Random Undersampling
rus = RandomUnderSampler(random_state=42)
X_train_rus, y_train_rus = rus.fit_resample(X_train, y_train)

svm_rus = SVC()
svm_rus.fit(X_train_rus, y_train_rus)
y_pred_rus = svm_rus.predict(X_test)
print("\nAfter Random Undersampling:")
print(classification_report(y_test, y_pred_rus))

Learning Curves: Diagnosing Bias and Variance

Learning curves help visualize how model performance changes with increasing training data, aiding in diagnosing underfitting or overfitting issues.

Copyimport numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import learning_curve
from sklearn.svm import SVC
from sklearn.datasets import make_classification

# Generate a dataset
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)

# Define the model
model = SVC(kernel='rbf', random_state=42)

# Calculate learning curves
train_sizes, train_scores, test_scores = learning_curve(
    model, X, y, cv=5, n_jobs=-1, 
    train_sizes=np.linspace(0.1, 1.0, 10),
    scoring='accuracy'
)

# Calculate mean and standard deviation
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)

# Plot learning curves
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_mean, label='Training score', color='

Response:

Learning Curves: Diagnosing Bias and Variance

Learning curves help visualize how model performance changes with increasing training data, aiding in diagnosing underfitting or overfitting issues.

Copyimport numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import learning_curve
from sklearn.svm import SVC
from sklearn.datasets import make_classification

# Generate a dataset
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)

# Define the model
model = SVC(kernel='rbf', random_state=42)

# Calculate learning curves
train_sizes, train_scores, test_scores = learning_curve(
    model, X, y, cv=5, n_jobs=-1, 
    train_sizes=np.linspace(0.1, 1.0, 10),
    scoring='accuracy'
)

# Calculate mean and standard deviation
train_mean = np.mean(train_scores, axis=1)
train_std = np.std(train_scores, axis=1)
test_mean = np.mean(test_scores, axis=1)
test_std = np.std(test_scores, axis=1)

# Plot learning curves
plt.figure(figsize=(10, 6))
plt.plot(train_sizes, train_mean, label='Training score', color='blue')
plt.fill_between(train_sizes, train_mean - train_std, train_mean + train_std, alpha=0.1, color='blue')
plt.plot(train_sizes, test_mean, label='Cross-validation score', color='red')
plt.fill_between(train_sizes, test_mean - test_std, test_mean + test_std, alpha=0.1, color='red')

plt.title('Learning Curves')
plt.xlabel('Training Examples')
plt.ylabel('Score')
plt.legend(loc='best')
plt.grid(True)
plt.show()

Feature Importance: Understanding Model Decisions

Feature importance helps identify which features contribute most to a model's predictions, providing insights into its decision-making process.

Copyfrom sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
import numpy as np
import matplotlib.pyplot as plt

# Generate a dataset with known feature importances
X, y = make_classification(n_samples=1000, n_features=10, n_informative=3, 
                           n_redundant=0, n_repeated=0, n_classes=2, 
                           random_state=42)

# Train a Random Forest classifier
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X, y)

# Get feature importances
importances = rf.feature_importances_
feature_names = [f'Feature {i}' for i in range(X.shape[1])]

# Sort features by importance
feature_importance = sorted(zip(importances, feature_names), reverse=True)

# Plot feature importances
plt.figure(figsize=(10, 6))
plt.bar(range(X.shape[1]), [imp for imp, _ in feature_importance])
plt.xticks(range(X.shape[1]), [name for _, name in feature_importance], rotation=45)
plt.title('Feature Importances')
plt.xlabel('Features')
plt.ylabel('Importance')
plt.tight_layout()
plt.show()

# Print feature importances
for importance, name in feature_importance:
    print(f'{name}: {importance:.4f}')

Ensemble Methods: Combining Models for Better Performance

Ensemble methods combine multiple models to create a more robust and accurate predictor, often outperforming individual models.

Copyfrom sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, VotingClassifier
from sklearn.svm import SVC
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# Generate a dataset
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Define individual models
rf = RandomForestClassifier(n_estimators=100, random_state=42)
gb = GradientBoostingClassifier(n_estimators=100, random_state=42)
svm = SVC(kernel='rbf', probability=True, random_state=42)

# Create a voting classifier
voting_clf = VotingClassifier(
    estimators=[('rf', rf), ('gb', gb), ('svm', svm)],
    voting='soft'
)

# Train and evaluate individual models and the ensemble
models = [rf, gb, svm, voting_clf]
model_names = ['Random Forest', 'Gradient Boosting', 'SVM', 'Voting Classifier']

for model, name in zip(models, model_names):
    model.fit(X_train, y_train)
    y_pred = model.predict(X_test)
    accuracy = accuracy_score(y_test, y_pred)
    print(f'{name} Accuracy: {accuracy:.4f}')

Additional Resources

For further exploration of machine learning evaluation metrics and techniques, consider the following resources:

  1. "A Survey of Predictive Modelling under Imbalanced Distributions" by Branco et al. (2016) ArXiv: https://arxiv.org/abs/1505.01658
  2. "Beyond Accuracy: Precision and Recall" by Powers (2011) ArXiv: https://arxiv.org/abs/2101.08458
  3. "ROC Analysis in Pattern Recognition: A Tutorial" by Fawcett (2004) ArXiv: https://arxiv.org/abs/cs/0303033

These papers provide in-depth discussions on various aspects of model evaluation and handling imbalanced datasets in machine learning.

More in Model evaluation and validation

  1. Stratified K-Fold Cross-Validation in Python11 min

    Stratified K-Fold cross-validation is an essential technique in machine learning for evaluating model performance. It addresses the limitations of simple...

  2. Regression Error Metrics with Python Code Examples8 min

    Mean Squared Error is a fundamental regression metric that measures the average squared difference between predicted and actual values. It heavily penalizes...

  3. The Dark Side of Cross-Validation in Python11 min

    Cross-validation is a widely used technique in machine learning for model evaluation and selection. However, it's not without its pitfalls. This presentation...

  4. Precision-Recall Plots in Python13 min

    Precision-Recall plots are powerful tools for evaluating binary classification models, especially when dealing with imbalanced datasets. These plots help...

  5. Understanding Confusion Matrices in Machine Learning8 min

    A confusion matrix is a fundamental evaluation metric in machine learning that tabulates the performance of a classification model by comparing predicted...

  6. Precision-Recall Plots for Classifier Evaluation9 min

    Precision-Recall plots are powerful tools for evaluating the performance of classification models. They provide insights into the trade-off between precision...