Skip to content
Machine Learning
Classification 9 min read

Classification Metrics Beyond Accuracy

Why accuracy lies on imbalanced data, and how to read confusion matrices, precision, recall, F1, ROC curves, and precision-recall curves instead.

Download notebook Open Google ColabIn Colab: File → Upload notebook → pick the downloaded file.

Accuracy is the first metric everyone learns — and the first one that betrays them. On real-world classification problems (fraud, disease, churn) the classes are rarely balanced, and a model can score 95%+ accuracy while being completely useless. This lesson gives you the full evaluation toolkit: the confusion matrix, precision and recall, F1, ROC/AUC, and the precision-recall curve.

The accuracy trap

Suppose only 5% of transactions are fraudulent. Here's a "model" that never predicts fraud at all — it just answers "legit" every time:

Python — runs in your browser

95% accuracy, zero frauds caught. Any metric that rewards this behavior can't be trusted on imbalanced data. To do better we need to look at which kinds of mistakes the model makes — not just how many.

The confusion matrix: four kinds of outcome

For a binary problem, every prediction lands in one of four cells:

  • True Positive (TP) — predicted positive, actually positive
  • False Positive (FP) — predicted positive, actually negative (a false alarm)
  • False Negative (FN) — predicted negative, actually positive (a miss)
  • True Negative (TN) — predicted negative, actually negative

Accuracy is (TP + TN) / total — it lumps both error types together. The confusion matrix keeps them separate:

Python — runs in your browser

Rows are the truth, columns are the predictions. The diagonal is what the model got right; the off-diagonal cells are the two flavors of mistake.

Precision vs recall: which mistake hurts more?

Two metrics zoom in on the positive class, each punishing a different error:

Precision = TP / (TP + FP) — of everything I flagged as positive, how much really was? High precision = few false alarms.

Recall = TP / (TP + FN) — of everything that is positive, how much did I catch? High recall = few misses. (Also called sensitivity.)

Which one matters depends entirely on the cost of each mistake:

  • Spam filtering — a false positive means a real email (maybe a job offer) lands in spam. That's the expensive mistake, so optimize precision.
  • Cancer screening — a false negative means telling a sick patient they're healthy. That's catastrophic, so optimize recall; a few false alarms that trigger a follow-up test are an acceptable price.

A memory hook

Precision asks "when I speak, am I right?" Recall asks "did I find them all?" You can always get perfect recall by flagging everything — at the cost of terrible precision. The two pull against each other.

F1 and the threshold tradeoff

The F1-score is the harmonic mean of precision and recall:

F1 = 2 · (precision · recall) / (precision + recall)

The harmonic mean is deliberately harsh: if either precision or recall is near zero, F1 is near zero too. Use it when you want a single number that balances both — the "do nothing" fraud model above has an F1 of exactly 0.

Most classifiers actually output a probability, and the default 0.5 cutoff is just a choice. Moving the threshold trades precision for recall:

Python — runs in your browser

Lower the threshold and recall climbs (you flag more) while precision drops. For a per-class summary of everything at once, classification_report prints precision, recall, F1, and support for each class:

from sklearn.metrics import classification_report
print(classification_report(y_te, model.predict(X_te),
                            target_names=["malignant", "benign"]))

ROC curve and AUC

Instead of picking one threshold, the ROC curve sweeps through all of them, plotting the true-positive rate (recall) against the false-positive rate at every cutoff. The AUC (area under the curve) summarizes it: 1.0 is a perfect ranker, 0.5 is coin-flipping.

Python — runs in your browser

A nice property of AUC: it doesn't depend on any particular threshold, so it measures how well the model ranks positives above negatives.

The PR curve: when imbalance is heavy

ROC has a blind spot. The false-positive rate divides by the number of negatives — and when negatives are 95%+ of the data, even thousands of false alarms barely move the curve. ROC-AUC then looks flattering while precision is actually awful.

The precision-recall curve plots precision against recall across thresholds, and both quantities focus on the positive class — so it stays honest under heavy imbalance. Rules of thumb from practice:

  • Roughly balanced data (20–80% positive) — ROC-AUC and PR-AUC both work.
  • Rare positives (under ~5%) — prefer the PR curve and average precision; ROC-AUC tends to overestimate how good the model is.
  • Very little data — every metric becomes unstable; treat all scores with suspicion.
from sklearn.metrics import PrecisionRecallDisplay
PrecisionRecallDisplay.from_estimator(model, X_te, y_te)

Check your understanding

5 questions · free
  1. Q1.A dataset is 98% negative. A model predicts 'negative' for every sample. What are its accuracy and recall for the positive class?

  2. Q2.In a cancer screening system, which mistake is usually the most dangerous?

  3. Q3.You lower a classifier's decision threshold from 0.5 to 0.2. What typically happens?

  4. Q4.Why is the PR curve preferred over ROC when positives are very rare (under 5%)?

  5. Q5.What does F1 = 0.0 tell you when accuracy is 95%?

Exercise: Pick a threshold for a screening model

Using the breast-cancer model from this lesson, treat malignant (label 0) as the positive class of a screening tool. Find the highest probability threshold that still achieves recall ≥ 0.95 for malignant cases, and report the precision you get at that threshold. Why would a hospital prefer this over the default 0.5 cutoff?

Next: the workhorse classifier behind those probability scores — logistic regression, the sigmoid, and why it needs a different loss than MSE.