Measuring a classifier: precision and recall
Accuracy can look great while the model misses every case that matters. The confusion matrix, precision and recall show what really happened.
In 60 seconds
Measuring a classifier: precision and recall
Accuracy can look great while the model misses every case that matters. The confusion matrix, precision and recall show what really happened.
The confusion matrix
| Predicted: negative | Predicted: positive | |
|---|---|---|
| Actually negative | True negative (TN): correctly left alone | False positive (FP): a false alarm |
| Actually positive | False negative (FN): a missed case | True positive (TP): correctly caught |
Precision and recall
- Precision = TP / (TP + FP). Of all the alarms raised, how many were real? Low precision means many false alarms.
- Recall = TP / (TP + FN). Of all the real cases, how many did we catch? Low recall means many missed cases.
- F1 combines the two into one number (their harmonic mean). It is only high when both are high.
from sklearn.metrics import confusion_matrix, precision_score, recall_score, accuracy_score
# 1 = positive (the rare case we care about), 0 = negative. Made-up labels.
actual = [0, 0, 0, 0, 0, 0, 0, 1, 1, 1]
predicted = [0, 0, 0, 0, 0, 1, 0, 1, 1, 0]
tn, fp, fn, tp = confusion_matrix(actual, predicted).ravel()
print("TN", tn, " FP", fp, " FN", fn, " TP", tp)
print("accuracy ", accuracy_score(actual, predicted))
print("precision", tp / (tp + fp), "=", precision_score(actual, predicted))
print("recall ", tp / (tp + fn), "=", recall_score(actual, predicted))Which one matters more?
| Situation | Worse mistake | Lean towards |
|---|---|---|
| Screening for a serious disease, followed by a proper test | Missing a sick person (FN) | Higher recall |
| Flagging bank transactions for a quick check | Missing fraud (FN), within a limit of checks staff can handle | Recall, with precision kept workable |
| Spam filter | A real email hidden in spam (FP) | Higher precision |
| Auto-blocking an account with no human review | Blocking an innocent person (FP) | Higher precision, or add human review |
Other habits for rare classes
- Split with
stratify=yso the rare class appears in every set. - Always report the confusion matrix next to any single number.
- Compare against the "always say negative" baseline.
- Some models accept
class_weight="balanced", which makes mistakes on the rare class count more in training.
Watch and read more
Lab
A made-up fraud dataset where a do-nothing model looks 98% accurate, a real model measured with precision and recall, and the effect of a lower threshold.
The problem
The starter generates made-up transactions with a fixed seed. About 2% are fraud. The numbers are invented for practice and do not describe any real bank.
- Run it. It trains a scaled logistic regression and prints accuracy.
- For the do-nothing model that always predicts 0, set
dumb_accanddumb_recallon the test rows. - For
model, setlr_precisionandlr_recallon the test rows. - Make
low_pred: predict 1 when the model's fraud probability is at least 0.2. Setlow_precisionandlow_recall. - Print the confusion matrix for both thresholds. In two sentences, say which threshold you would pick if each flagged transaction gets a quick human check, and why.
Practice lab
Edit the code and run it. Python runs in your browser — nothing is sent to our server.
No output. Add print(...) to see values.
You are done when
Hard questions
Try to answer before you reveal. If you can answer these, you understood the lesson.
Q1Why is choosing the 0.2 threshold by looking at these test results not fully honest, and what would you do instead?Reveal
Any threshold chosen by looking at the test results is tuned to that test set, so the reported numbers become optimistic. Choose the threshold on a validation set, or with cross-validated probabilities on the training data, then apply it once to the test set.
Q2The test set has only a few dozen fraud cases. What does that mean for the recall number?Reveal
Each fraud case changes recall by several percentage points, so the number is rough. Report the counts (for example 20 of 24 caught), not just the percentage, and be careful about small differences between models. More fraud examples, or repeated splits, give steadier numbers.
Questions people ask
Which class should be "positive"?
By habit, the rare class you care about catching: fraud, disease, defect. Precision and recall are then about that class. scikit-learn treats label 1 as positive by default.
Is there a single best measure?
No. Choose the measure that matches the cost of each mistake in your situation, and always show the confusion matrix so others can see the full picture.
What is a precision-recall curve?
A chart of precision against recall at every possible threshold. It shows the whole trade-off at once, and helps you pick a threshold. scikit-learn has precision_recall_curve.
Can I choose the threshold on the test set?
No, that is a choice like any other. Choose it with validation data or cross-validation, then report the test result once.
Lesson test
5 questions. Get 3 right (60%) to pass and complete this lesson.