Cross-Validation

You hold out a test set, train, and score 91%. But was that 91% real, or did you get lucky with which rows happened to land in the test set? With a single split you can't tell — and if the test set is small, the score wobbles alarmingly from one random split to the next. A model that looks great on one split can look mediocre on another, and you'd never know.

Cross-validation fixes this by not trusting any single split. It rotates the held-out portion through the whole dataset, so every row gets a turn being evaluated, and averages the scores into an estimate that is far more stable. It is the backbone of honest model evaluation, built on top of the train / validation / test split.

k-fold cross-validation

Split the data into k equal parts, or folds. Then run k rounds: each round holds out one fold to score on and trains on the other k-1. Every fold is the validation set exactly once, and the final estimate is the average of the k scores. The diagram shows k = 5: each row is one round, the highlighted block is that round's held-out fold.

With k = 5 or k = 10 (the usual choices) every row contributes to the score, so you use the data far more efficiently than a single hold-out — and the average of five or ten estimates has much less variance than any one of them. The price is compute: you train the model k times instead of once.

Three variations you'll actually use

The choice of k is itself a bias–variance tradeoff, applied to the estimate rather than the model: small k (say 2 or 3) trains on less data, biasing the estimate pessimistically; large k trains on nearly all the data (low bias) but the highly overlapping training sets make the fold scores correlated, raising the variance of their average. k = 5 or 10 is the sweet spot precisely because it balances the two.

It feels backwards — surely training on n-1 points every time should give the most reliable estimate? The subtlety is that LOOCV's n training sets differ by only a single point, so the n fitted models are almost the same model, and their errors are strongly correlated. The average of many correlated numbers doesn't shrink its variance the way the average of independent numbers does. Ten-fold CV, whose training sets overlap less, produces less correlated fold scores and so a lower-variance average — which is a large part of why practitioners rarely bother with LOOCV.

Cross-validation is for choosing and tuning your model — comparing algorithms, picking hyperparameters. The moment you use CV scores to make decisions, those folds have informed your choices, so a good CV score is not an unbiased estimate of future performance. You still need a final, untouched test set, locked away until the very end, to get an honest number. Reporting your best cross-validation score as the model's real-world accuracy is a classic way to overstate it — the test set exists precisely to keep you honest after all the tuning is done.

Learn this on Kaggle

Kaggle Learn's Intermediate Machine Learning course has a dedicated cross-validation lesson where you run k-fold with scikit-learn's cross_val_score and see the fold-to-fold spread for yourself. It's the quickest way to feel why one split isn't enough.