Concepts / Information Leakage in Cross-Validation

Information Leakage in Cross-Validation

Information leakage happens when test-set information influences training, which makes performance estimates overly optimistic.

  • Programming
Interactive lab

Try it: K-Fold Cross-Validation and Model Selection

How hold-out and k-fold cross-validation choose among candidate models: each fold takes a turn as the validation set, the fold errors are averaged, the lowest average picks the model, and only then is the untouched test set used once — while tuning on the test set would report an optimistic number.

How it works

  1. Set 10 test points aside; they take no part in any choice.
  2. Optionally shuffle the 20 development points (seeded), then cut them into k folds (hold-out: one chunk validates, the rest trains).
  3. For every round, train each candidate polynomial on the other folds and measure its validation MSE on the held-out fold.
  4. Average each candidate's fold errors (with repeated shuffling: average the p run scores; p × k fits per candidate).
  5. Select the candidate with the lowest average, retrain it on all development points, and evaluate it once on the test set.
  6. For contrast, show which candidate the test set itself would have picked — that figure is leaked and optimistic.

Default run (12 steps): 20 development points (sorted by x as they arrived) and 10 test points set aside. Candidates: polynomial degree 0, 1, 2, 3, 4, 5, 6. Plan: 5-fold cross-validation, shuffled with seed 1 → 5 fits per candidate (p × k = 1 × 5), 35 in total. … 5-fold cross-validation picks degree 3 (score 0.0768); its honest test MSE is 0.0889. Picking by test error would report degree 4 at 0.0868 — a leaked, optimistic figure.

Simplified: One fixed toy dataset (20 development + 10 test points from sin(2πx) with noise) and polynomial least squares of degree 0–6 as the candidate models. Shuffling uses a seeded mulberry32 Fisher–Yates; folds are contiguous chunks like scikit-learn's KFold. Hold-out uses the first of k chunks as the validation set.

Educational simulation

Loading the simulation…

A Suspiciously Good Score on Random Data

Imagine a dataset in which every feature and the target are pure random noise. There is nothing real to learn. Now suppose you run a model on this data, score it with cross-validation, and the score comes back looking strong. A reasonable first reaction is that the model must have found something. This article is about why that reaction can be exactly wrong, and about the one habit that prevents it.

The cause is usually not a bug in the model or in the scoring code. It is a subtle ordering mistake in the workflow: a step that should have been repeated inside each cross-validation loop was performed once, on the full dataset, before the loop started. Understanding why that matters requires being precise about what cross-validation is supposed to measure.

Why Feature Selection Feels Harmless

A common belief is that feature selection is just a cleaning step that happens before modeling. It can therefore be done once on the full dataset, and cross-validation can then be run on the reduced data. The belief sounds tidy. Feature selection looks at inputs and the target, keeps the most useful columns, and passes the result along. Where would the harm be?

What Cross-Validation Is Supposed to Measure

Definition

Information leakage happens when test-set information influences training, which makes performance estimates overly optimistic.

Cross-validation is meant to estimate how a model performs on data it has never seen. The test fold is supposed to play the role of unseen data. If the test fold has already influenced which features were chosen, it is no longer unseen. The step that looked harmless has quietly used the answers from the test fold, and the score you read off at the end is no longer an honest forecast of performance on new data.

The important detail is that the leak does not require anyone to look at the test rows on purpose. It is enough that the selection procedure was fitted on the whole dataset. Selection keeps features that are correlated with the target. The test rows are part of the whole dataset, so the features that survive are tuned in part to the test rows.

Tracing the Leak Through a Leaky Workflow

The diagram below traces where test-fold information enters the workflow when selection runs on the full dataset before splitting. Follow the arrows from the raw data to the final score, and notice that the selector touches every row before any fold exists.

Full datasetall rows, train and testFeature selectionfitted on every rowSelected featurestuned partly to test rowsCross-validationsplitssplit happens afterselectionReported scoreoptimistic estimatelabels and inputskeeps columnsreduced dataaveraged test scores
Where does test-fold label information enter the pipeline when feature selection runs on the full dataset before splitting, and how does that change which features are chosen?

In this workflow the test rows have already shaped the set of features before any split is made. When cross-validation then evaluates the model, the held-out folds are no longer unseen. The features were chosen partly because they happened to correlate with those very rows, so the score is inflated.

Worked Example: Noise Data With a Leaky Selector

Worked example

Selecting features on the full dataset

A dataset contains many features and a target, and every value is random noise. The workflow selects the 10 features most correlated with the target on all rows, then runs cross-validation on those 10 features. Why can the reported score look strong?

  1. 1
    Step 1: Note that there is no real signal

    Every feature and the target are random, so no feature truly predicts the target on new data.

  2. 2
    Step 2: Run selection on all rows

    The selector ranks features by correlation with the target using every row, including the rows that will later serve as test folds.

  3. 3
    Step 3: Keep the strongest correlators

    With many random features, some will correlate with the target by chance. Selection keeps those chance correlations, and some of them are chance correlations that also hold in the test rows.

  4. 4
    Step 4: Cross-validate on the reduced data

    Each test fold was part of the selection step, so it is no longer unseen. The model is scored on rows whose answers helped choose its features.

  5. 5
    Step 5: Read the score

    The score looks strong because the features were tuned to the test rows, not because the model learned a real pattern.

Result

The strong score is an overly optimistic estimate produced by information leakage from the test folds into feature selection.

Mistakes That Create the Leak

  • Common mistake

    Running feature selection on the full dataset before calling cross-validation

    What it looks like
    selector.fit(X, y) on all rows, then cross_val_score on X_selected
    Why it fails

    Every test fold has already influenced which columns were kept, so it is no longer unseen data.

    Do this instead

    Place the selector and the model in one Pipeline and pass the Pipeline to cross-validation.

  • Common mistake

    Assuming that a leak needs someone to look at the test rows on purpose

    Why it fails

    The leak comes from the selection procedure being fitted on the whole dataset, not from deliberate peeking.

    Do this instead

    Check the order of operations, not your intentions.

  • Common mistake

    Dismissing a lower cross-validation score after fixing the workflow

    Why it fails

    A lower score is often the honest result once the test folds are kept unseen.

    Do this instead

    Treat the more pessimistic score as the more trustworthy estimate.

Refitting Selection Inside Each Split

A Pipeline chains several steps, such as a feature selector followed by a model, into a single object. When that object is passed to cross-validation, each fold triggers its own fit. The selector is fitted on the training folds of that fold only, the model is fitted on the same reduced training data, and then both are applied to the test fold. The selector never sees the test fold during its fit, because the pipeline does not allow it to.

Split kchoose training and testfoldsFit selectortraining folds onlyFit modelon reduced training dataApply to test foldtransform only, no fittingScore test foldone score per splittraining foldselected columnsfitted selector and modelpredictions
For each CV split, what is fitted on the training fold, what is only transformed on the test fold, and in what order do these steps repeat?

The loop then repeats for the next split with new training and test folds. Each repetition starts from the training portion of that split, so the set of selected features can differ from one split to another. That variation is part of the honest picture: the pipeline is measuring how the whole procedure behaves on unseen folds.

Leaky Versus Pipeline-Based Workflows Side by Side

The two workflows perform the same kinds of steps. What differs is the moment at which selection happens relative to the split, and therefore which rows each step touches. The comparison below lays them out in two columns.

Select features onfull datatest rows influenceselectionSplit into foldssplit comes firstSplit into foldsafter selectionFit selector ontraining foldsper splitFit model per foldon pre-selected featuresFit model on trainingfoldssame reduced dataApply both to testfoldno fitting on test rowsreduced dataeach foldeach foldselected columnsfitted pipeline
How do the leaky and correct workflows differ in which data each step touches, and where does the test set get used?

Building a Pipeline That Keeps Folds Separate

The code below is an illustrative sketch of the Pipeline pattern described above. It places a feature selector and a model in one object and passes that object to cross-validation, so each split refits the selector on its own training folds.

python
Notes on the code
  • Pipeline chains the selector and the model into one object
  • SelectKBest is the selection step, fitted per fold
  • cross_val_score refits the whole pipeline inside each split

The crucial point is not the specific selector or model. The key is that the selection step lives inside the object that cross-validation refits. Written this way, the test fold is only ever transformed by the selector, never used to decide which features it keeps.

Checking Your Understanding of the Leak

MEDIUM

A colleague runs SelectKBest on the full feature matrix, then calls cross-validation on the reduced matrix. Before reading further, predict at which step test-fold information first enters the workflow, and say whether the reported score is likely to be too high or too low. Then explain how moving the selector into a Pipeline changes that answer.

Hints
  • Ask which rows the selector was fitted on, not which model is used.
  • Think about whether each test fold was already part of the selection decision.
  • Consider what the Pipeline makes cross-validation refit on each split.

Key Takeaways

  • Information leakage happens when test-set information influences training, which makes performance estimates overly optimistic.
  • Feature selection fitted on the full dataset before cross-validation leaks test-fold information into the selected features, even without anyone deliberately examining the test rows.
  • A Pipeline that includes the selector and the model, passed to cross-validation, refits the selection on the training folds of each split, so the test fold is only transformed and never used to choose features.
  • A lower, more pessimistic cross-validation score can be the honest result and should not be dismissed as a failure.
  • The main lesson concerns where a step is fitted, not which step is used.

Related concepts

More concepts starting with I