JA EN
LearnMachine Learning Basics
·★ MEMBER·10 min read

Data Leakage and Experiment Hygiene — When the Score Is Too Good, Suspect It

When a model scores better than you expected, that is not good news yet. This article splits data leakage into five concrete shapes — outcome-derived columns, preprocessing before the split, time running backwards, duplicates and groups, and a worn-out test set — then covers the detection moves that actually find them and the experiment records that let you dissect the day the number jumped.

ModalitytextTaskevaluation

The student whose mock exam score doubled

A student scores in the 99th percentile on a practice test. Last month they were at the median. Nobody can explain it — until someone notices that the practice test was the same worksheet handed out the week before, answer key included. The student did not get smarter. Only the measurement moved.

That is almost always what is happening when a machine learning model scores better than you expected. Data leakage is when information that would not actually be available at prediction time slips into training, validation, or model selection.

What makes leakage nasty is that it only ever pushes the score in the flattering direction. A normal bug makes numbers worse, and worse numbers get investigated. Leakage makes them better, so nobody investigates. It ships. The 0.95 AUC on your laptop becomes 0.6 in production, and because the fault lives in how you measured rather than in the model, no amount of model improvement fixes it.

Why we split data into train, validation, and test in the first place is covered in Overfitting and Evaluation Design. This article picks up one step later: the situation where you split it correctly and it is still broken. There are five shapes this takes.

One line that defines leakage

Before the taxonomy, keep exactly one test in your head.

Picture the instant this model serves a prediction in production. Using only the information you actually have at that instant, could you construct this feature?

If you could not, it is leakage. Which means hunting leakage is not a feat of cleverness — it is a timestamp audit. Walk the columns one at a time and ask when each value becomes known. That alone catches most of it.

Shape 1: Columns that grew out of the outcome

A churn model with a "visits to the cancellation page" column. A deterioration model with an "ICU transfer" flag. An equipment failure model with a repair ticket number. Every one of these is a column that only gets filled in after the event you are trying to predict has already happened.

In the database they sit on the same row as the label, perfectly innocent-looking. SELECT * picks them up. The model happily uses that column and nothing else, and returns a near-perfect score.

Finding them is unglamorous: list the columns and annotate each with does this value settle before or after prediction time? Watch especially for mutable tables that overwrite in place. If a customer table keeps only the current status and no history, then a row you pulled for last January is carrying today's value. In that case the entire column leaks for every row.

Shape 2: Preprocessing before the split

This is the trap that well-intentioned people step in. Take standardization.

zi=xiμallσall,μall=1Ni=1Nxiz_i=\frac{x_i-\mu_{\text{all}}}{\sigma_{\text{all}}},\qquad \mu_{\text{all}}=\frac{1}{N}\sum_{i=1}^{N}x_i
(1)

Here xix_i is one feature's value on row ii, μall\mu_{\text{all}} and σall\sigma_{\text{all}} are the mean and standard deviation computed over all the data, and NN is the total row count. In words: you normalized the whole dataset and then cut it into train and test.

Notice that test rows participated in computing μall\mu_{\text{all}}. The distribution of the test set has bled into training. The correct move is to compute μtrain,σtrain\mu_{\text{train}}, \sigma_{\text{train}} from training data only and apply them to the test set, learning nothing from it.

For standardization alone the damage is usually small. What makes it worth caring about is that the same mistake generalizes:

The last two do not merely inflate the score; they void the experiment. Generate 3,000 columns of pure noise, select the 20 most correlated with the target across the full dataset, then cross-validate: AUC can land north of 0.8. The features are random numbers. The selection step looked at yy, and that yy included the validation rows, so the surviving 20 columns are simply "the noise that happened to resemble the answers." SMOTE fails the same way — oversample before splitting and synthetic points interpolated from test rows end up in training. That is copying the answer key with a blur filter on.

FIG 1With an honest split, raising the polynomial degree (the model's capacity) sends test error climbing while training error keeps falling. Under leakage the two curves never separate — and that refusal to separate is itself the symptom

If your rows carry timestamps, a random split is off the table. Split randomly and you train on August to predict July — a configuration that will never occur in production.

What's behind this

§

Members-only from here

371 walkthroughs, 26 textbook chapters, 48 student units and 6 close readings — all included for $4.99/mo, with three new explainers every day. Cancel any time; access runs to the end of the period.

Already a member? Sign in to keep reading

Comments

Sign in to comment