2.6.15 · D2Model Evaluation & Selection

Visual walkthrough — Cross-validation pitfalls and nested CV

2,238 words10 min readBack to topic

Before we begin, three plain-word anchors so no symbol appears un-earned.

Everything below is about one trap: choosing the knob by looking at scores, then reporting one of those same scores as your final grade.


Step 1 — What cross-validation actually measures

WHAT. We have a pile of data. We cannot test a model on the same cards it trained on (it could just memorise them). So we chop the pile into equal groups called folds. We train on of them and test on the one left out — then rotate, so every card gets a turn as the test card.

WHY. Rotating means every card is used for testing exactly once, so we squeeze an honest test out of a small pile. The average of the test errors is our estimate.

PICTURE. In the figure, the pile is split into 5 folds. The grey fold is held out; the coloured folds train the box. We slide the held-out fold along and average the 5 heights.

Figure — Cross-validation pitfalls and nested CV

  • ::: the number of folds (here 5).
  • ::: "all data except fold " — the training cards.
  • ::: fold alone — the held-out test cards.
  • ::: the box trained with knob setting on those training cards.
  • ::: how wrong that box is on the held-out fold.
  • ::: average the 5 heights into one number.

This single number, for one fixed knob setting, is honest. The trouble starts when we have many knob settings. See 2.6.2-K-fold-cross-validation for the mechanics of this split.


Step 2 — Trying many knob settings

WHAT. We don't know the best knob, so we try a whole list of them: . For each one we run the Step-1 procedure and get a score .

WHY. Tuning is unavoidable — Ridge with the wrong is either useless or overfit (see 2.6.12-Hyperparameter-tuning-strategies). So we compute different heights, one per setting.

PICTURE. The figure shows one bar per knob setting. Each bar's height is that setting's CV error. They wiggle up and down because the folds are finite and a bit noisy.

Figure — Cross-validation pitfalls and nested CV

  • ::: how many settings we tried (the number of bars).
  • Each bar ::: an average-of-5 error, itself a slightly noisy measurement.

Key idea to hold: each bar is a random variable. Its height = true error + a little luck (which cards landed in which fold). Some bars are lucky-low; some unlucky-high.


Step 3 — Picking the winner, and the bias that sneaks in

WHAT. We pick the setting with the smallest bar:

  • ::: "give me the that produces the minimum," not the minimum value itself.
  • ::: the winning knob setting (star = chosen).

WHY the score is now dishonest. Here is the whole trap in one sentence: the minimum of noisy bars sits below the true average, because we specifically hunted for the bar that got lucky. If we then report that minimum height as our performance, we are reporting luck as skill.

PICTURE. The figure separates each bar into its true height (dashed line) and its luck (the wiggle). The chosen bar (coral) is the one whose luck pushed it down. Its reported height is below the honest dashed line — that gap is the optimistic bias.

Figure — Cross-validation pitfalls and nested CV

  • ::: the lucky-low winner.
  • ::: "expected value" — the long-run average if we repeated the whole experiment forever.
  • The "" ::: the minimum is always at or below the mean. That inequality is the bias.

The bias gets worse when: more settings tried (, more chances to get lucky), smaller data (fatter wiggles), or more flexible models (easier to fit the folds' noise — connects to 2.7.3-Bias-variance-tradeoff and 2.6.16-Data-leakage).


WHAT. We wrap the whole "try knobs and pick a winner" routine (Steps 2–3) inside an outer cross-validation whose folds are locked away and never consulted during tuning.

WHY. In real life you tune on the data you have, then deploy on new data. So we should measure the entire tuning-plus-training pipeline on data it never influenced. The outer fold plays the role of "brand-new data."

PICTURE. Two nested rings. The outer ring peels off a test fold (grey, sealed). The inner ring lives entirely inside the remaining data and does the Step 2–3 search there. The sealed grey fold watches nothing.

Figure — Cross-validation pitfalls and nested CV

For each outer fold :

  • ::: number of outer folds (the sealed-test rotation).
  • ::: everything except outer fold — the search happens only here.
  • ::: the sealed fold, opened once at the very end.

Step 5 — Inner loop: search the knob, but only inside the outer-train pile

WHAT. Inside we run an ordinary -fold CV over the knob list and pick a per-fold winner.

WHY. This is Step 1–3 again, but confined. It picks the best for this outer fold's training data only. Different outer folds may crown different winners — that is fine and expected.

PICTURE. Zoom into one outer-train pile. It is re-chopped into inner folds; the bars-and-winner picture from Step 3 replays here, sealed away from the grey outer test.

Figure — Cross-validation pitfalls and nested CV

  • ::: inner-fold count.
  • ::: the -th inner held-out slice (inside outer-train).
  • ::: outer-train minus that inner slice — the inner training cards.
  • ::: the knob winner for outer fold . The superscript says it can differ per outer fold.

Step 6 — Open the sealed fold and score once

WHAT. Take the winner , train a fresh box on the whole outer-train pile, and finally test it on the sealed outer fold .

WHY. This is the first and only time is touched. Because it never entered the knob search, its error is an honest sample of true generalisation for the whole pipeline (tune-then-train), not just for one lucky knob.

PICTURE. The grey seal breaks. One clean height is recorded — no minimum, no cherry-picking, just one measurement.

Figure — Cross-validation pitfalls and nested CV

  • ::: box retrained with the inner-chosen knob on all outer-train cards.
  • ::: the sealed fold — never a witness to the search.
  • ::: one honest height for outer fold . No anywhere in sight.

Step 7 — Average the sealed scores = the honest number

WHAT. Rotate the sealed fold through all positions, collect the clean heights, average them.

WHY. Each height was a Step-6 measurement on data blind to its own tuning. Their average estimates the expected error of the entire procedure. No hidden minimum survived into this number, so the Step-3 inequality no longer bites.

PICTURE. The outer heights from each sealed fold stacked side by side; a single flat line marks their average — the reported result.

Figure — Cross-validation pitfalls and nested CV

  • ::: the number you actually publish.
  • The sum ::: the sealed heights from Step 6.
  • ::: average over outer folds.

Step 8 — The degenerate & edge cases (so nothing surprises you)

WHAT / WHY / PICTURE, one panel each in the figure below:

  1. One knob only (). No search, no hunting for luck. Step 3's inequality collapses ( of one number is the mean). Standard CV is already honest — nesting adds cost for no gain.
  2. Preprocessing (scaling, feature-picking) counts as tuning. If you scale using the whole pile, the sealed fold leaked its statistics into training → biased again. Every learned transform must live inside the inner loop. This is the Cawley–Talbot 91%→73% collapse; see 2.6.16-Data-leakage.
  3. Tiny data / many features. Fat wiggles (Step 3) → huge gap between and truth → nested CV matters most here, precisely when you can least afford to be fooled.
  4. Early stopping is tuning too. Choosing when to stop by watching a validation curve is a knob; it belongs inside the inner loop or on its own held-out slice — see 3.4.5-Early-stopping.
Figure — Cross-validation pitfalls and nested CV

The one-picture summary

Figure — Cross-validation pitfalls and nested CV

The whole argument in one frame: an outer ring that seals a test fold, an inner ring that hunts the best knob inside the rest, the sealed fold opened once for a clean score, and those clean scores averaged into . The biased shortcut (report the inner ) is drawn crossed out.

do NOT report

Full data pile

Outer split: seal one test fold

Inner CV on outer-train only

Pick best knob for this fold

Retrain on all outer-train

Open sealed fold: one clean score

Average clean scores

Honest reported error

Inner min score is biased

Recall Feynman retelling — say it like a story

Imagine a shop testing 4 radios. You play each radio in 5 rooms and average its static; the radio with the least static wins. But rooms are noisy — the winner might just have gotten quiet rooms by luck. So its winning score is too rosy. To get an honest grade, you keep a sealed room the shopping never entered. You do all your radio-shopping in the other rooms, crown a winner, then — only now — carry that winner into the sealed room and measure it once. Rotate which room is sealed, average those sealed measurements: that average is what the radio really does in a room it never influenced. The winning score from inside the shopping tells you which radio to buy, never how good it truly is. And if you "tuned" the antenna using every room including the sealed one, you cheated — tuning, scaling, feature-picking, and stopping-early all count as shopping and must stay outside the sealed room.


Self-test:

Why is biased low?
Because the minimum of noisy scores favours whichever setting got lucky-low; the min of random variables is their mean.
What does the outer loop estimate that standard CV cannot?
The error of the whole tune-then-train pipeline on data that never influenced tuning.
Which score do you publish — inner best or outer average?
The outer average ; the inner min only chooses the knob.
Where must feature scaling / selection happen?
Inside the inner loop, so the sealed outer fold never leaks its statistics.
When does nesting add no value?
When there is a single hyperparameter setting () — no search, no selection bias.