Machine learningLoading progress…

Imbalanced classes

Construct a leakage-resistant pipeline and select an evaluation procedure that reflects deployment.

Accuracy rewards ignoring the rare class

Fraud, disease, failures: the event you care about is rare. In this data about 5% of rows are positive. A model that answers "negative" to everything is right on 96% of the validation rows and finds none of the positives: recall is 0%. Accuracy is the share of all decisions that were right, so it is dominated by the majority class.

Read a confusion matrix instead. With counts: TP positives found, FN positives missed, FP negatives wrongly flagged, TN negatives correctly passed.

  • Recall = TP / (TP + FN): of the real positives, how many did we find?
  • Precision = TP / (TP + FP): of the cases we flagged, how many were real?

Always keep the counts next to the rates. "40% recall" of 5 positives and of 5,000 are very different claims.

Three knobs, one trade-off

The model below is a logistic regression on one feature. Trained normally, it flags a positive only when it is more than 50% sure, which for a rare class almost never happens: recall is 12.5% (5 of 40), accuracy 96.2%. Three levers change that.

  • Class weights make a missed positive cost more during training.
  • Resampling copies positives (or drops negatives) in the training data.
  • The decision threshold is the probability above which you flag a case. It can be moved after training without refitting.
Weight of a positive rowx1Decision threshold50%
modelaccuracyprecisionrecallF1TP/FP/FN/TN
Always say negative96%0%0%00/0/40/958
Your logistic model96.2%62.5%12.5%0.215/3/35/955

Validation rows: 998, of which 40 are positive (4%). Training set after your choices: 2002 rows.

Try each lever alone, then together. Watch recall rise and precision fall. The first row is the always-negative model on the same validation rows.

Weighting positives by 10 raises recall to 62.5% but precision falls to 16.6%: 126 negatives are flagged to catch 25 positives. Lowering the threshold to 15% gives recall 40% with precision 24.2%. Neither is "correct". The right point depends on what a miss and a false alarm cost.

Predict first. With the same trained model you raise the threshold from 50% to 80%. What happens to recall?

The common mistake, failing

Oversampling the whole table and then splitting copies the same positive into both sides. The validation set then holds copies of training positives. Switch the lab to "Before the split" with oversampling on: validation grows to 1879 rows of which 921 are positive, a class balance that does not exist in the real data, and the metrics describe a task you will never face. Resample inside the training fold only, and keep validation and test rows with the real class ratio.

Also split with the class ratio kept (stratified), otherwise a small random split can leave a fold with almost no positives, or none, and its recall is undefined.

Chapter context

Practical performance depends on the data boundary around training as much as on the estimator. Every learned preprocessing step is part of the model and must respect the same evaluation split.

Chapter reference: math, worked example & code

This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.

Math and notation

Treat the fitted object as preprocessing composed with prediction: model(x) = estimator(transform(x)). Fit both using the training data only. For an imbalanced binary task, report counts as well as rates so denominators remain visible.

Worked example

Training values [0,2] have mean 1. A test value is 100. If the mean is incorrectly fitted on all three values, it becomes 34. The test set has now changed the transformation applied to training examples. A separate 90-negative/10-positive dataset gives 90% accuracy but zero recall for always-negative predictions.

Reference code

The following example uses the Python standard library and does not call a remote service.

train, test = [0,2], [100]
assert sum(train)/len(train) == 1
assert sum(train+test)/len(train+test) == 34
assert 90/100 == .9
assert 0/10 == 0

Python examples are provided for study and local execution; this page does not execute Python.

Common mistakes

An excellent test score can reflect leakage. More hyperparameter trials can overfit a fixed validation set. Monitoring confidence alone does not measure real outcome quality.