By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
You’ve trained a machine learning model. Now what? Model evaluation is how you measure whether it’s actually useful—or just memorizing noise.
Why this matters in production:- A model with 99% accuracy might be useless if it only predicts the majority class (e.g., a fraud detector that never flags fraud).- A high-precision model (few false positives) might miss critical cases (low recall).- ROC-AUC tells you if your model is better than random guessing—critical for imbalanced datasets (e.g., medical diagnosis, fraud detection).
Real-world scenario:You’re building a credit card fraud detection system. Your model flags 100 transactions as fraudulent, but only 5 are real frauds. Is this good or bad? - Precision tells you: "Of the transactions I flagged, how many were actually fraud?" (5/100 = 5% precision → terrible).- Recall tells you: "Of all actual frauds, how many did I catch?" (If there were 10 real frauds, recall = 5/10 = 50% → missing half!).- F1-score balances both (harmonic mean of precision & recall).- ROC-AUC tells you: "How well does my model separate fraud from non-fraud?" (AUC=0.5 → random, AUC=1.0 → perfect).
If you ignore this:- Your model might look good on paper (high accuracy) but fail in production (e.g., missing all fraud cases).- You might waste resources chasing false positives (e.g., flagging legitimate transactions as fraud).- Stakeholders will lose trust in your model.
2 * (precision * recall) / (precision + recall)
scikit-learn
pandas
matplotlib
seaborn
import pandas as pd from sklearn.model_selection import train_test_split # Load dataset (example: credit card fraud) data = pd.read_csv("creditcard.csv") X = data.drop("Class", axis=1) # Features y = data["Class"] # Target (1=fraud, 0=legit) # Split into train/test (stratify to maintain class imbalance) X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.3, random_state=42, stratify=y )
from sklearn.linear_model import LogisticRegression model = LogisticRegression(max_iter=1000, class_weight="balanced") # Handles imbalance model.fit(X_train, y_train) y_pred = model.predict(X_test) # Hard predictions (0 or 1) y_proba = model.predict_proba(X_test)[:, 1] # Probabilities (for ROC-AUC)
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt cm = confusion_matrix(y_test, y_pred) disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=["Legit", "Fraud"]) disp.plot(cmap="Blues") plt.title("Confusion Matrix") plt.show()
Expected output:
[[85296 12] [ 30 112]]
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score accuracy = accuracy_score(y_test, y_pred) precision = precision_score(y_test, y_pred) recall = recall_score(y_test, y_pred) f1 = f1_score(y_test, y_pred) roc_auc = roc_auc_score(y_test, y_proba) print(f"Accuracy: {accuracy:.4f}") # 0.9995 (misleading!) print(f"Precision: {precision:.4f}") # 0.9032 (90% of flagged are fraud) print(f"Recall: {recall:.4f}") # 0.7887 (caught 79% of frauds) print(f"F1-Score: {f1:.4f}") # 0.8421 (balance of precision/recall) print(f"ROC-AUC: {roc_auc:.4f}") # 0.9850 (excellent separation)
from sklearn.metrics import RocCurveDisplay RocCurveDisplay.from_predictions(y_test, y_proba) plt.plot([0, 1], [0, 1], "k--") # Random guessing line plt.title("ROC Curve") plt.show()
What to look for:- Curve above the diagonal = better than random.- AUC > 0.9 = excellent model.
from sklearn.metrics import PrecisionRecallDisplay PrecisionRecallDisplay.from_predictions(y_test, y_proba) plt.title("Precision-Recall Curve") plt.show()
What to look for:- High area under curve = good model.- Precision drops as recall increases (trade-off).
import numpy as np # Try different thresholds thresholds = np.linspace(0, 1, 20) precisions = [] recalls = [] for t in thresholds: y_pred_adj = (y_proba >= t).astype(int) precisions.append(precision_score(y_test, y_pred_adj)) recalls.append(recall_score(y_test, y_pred_adj)) # Plot trade-off plt.plot(thresholds, precisions, label="Precision") plt.plot(thresholds, recalls, label="Recall") plt.xlabel("Threshold") plt.ylabel("Score") plt.legend() plt.title("Precision vs. Recall Trade-off") plt.show()
Key takeaway:- Lower threshold → higher recall, lower precision (more false positives).- Higher threshold → higher precision, lower recall (more false negatives).
fraud_model_v2.pkl
v2
v1
✅ Precision, recall, F1, ROC-AUC.
"What does an ROC-AUC of 0.7 mean?"
✅ Model is 70% better than random guessing at separating classes.
"How do you improve recall without hurting precision too much?"
✅ Lower the classification threshold (but monitor false positives).
"Why is F1-score better than accuracy for fraud detection?"
You’re building a spam classifier. Your model has: - Precision = 0.95 (95% of flagged emails are spam).- Recall = 0.80 (80% of actual spam is caught).
Question: What’s the F1-score? If you lower the threshold, what happens to precision and recall?
precision = 0.95 recall = 0.80 f1 = 2 * (precision * recall) / (precision + recall) # 0.8696 print(f"F1-Score: {f1:.4f}") # 0.8696
What happens if you lower the threshold?- Recall increases (more spam caught).- Precision decreases (more false positives).
Key Python Snippets:
from sklearn.metrics import ( accuracy_score, precision_score, recall_score, f1_score, roc_auc_score, confusion_matrix, RocCurveDisplay, PrecisionRecallDisplay ) # Confusion Matrix cm = confusion_matrix(y_true, y_pred) # Metrics 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) roc_auc = roc_auc_score(y_true, y_proba) # Plots RocCurveDisplay.from_predictions(y_true, y_proba) PrecisionRecallDisplay.from_predictions(y_true, y_proba)
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.