Cross-Validation Explained: 5 Folds, 1 Reliable Score

⚡ TL;DR: Cross-validation splits your data into k folds and trains k times, holding out a different fold each round. You get k scores instead of one, so you learn not just how well the model does but how much that number can be trusted.

A single train/test split gives you one number. That number depends on which rows happened to land in the test set — and on a small dataset, that luck can be worth several percentage points. Cross-validation removes the luck.

How cross-validation works

Five-fold cross-validation diagram showing each fold used as the test set exactly once across five training rounds
Five rounds, five models, five scores. Every row is used for training four times and for testing once.

Split the data into k equal parts, called folds. Then run k separate training rounds: each round holds out one fold for testing and trains on the other k−1. Average the k scores at the end.

✅ The key property: every row gets to be test data exactly once, and training data k−1 times. Nothing is wasted, and no single unlucky split can mislead you.

Read the spread, not just the average

This is the part most tutorials skip, and it is the main reason to bother with cross-validation at all.

Fold scoresMeanWhat it tells you
84, 83, 85, 84, 8484%Stable. You can quote 84% with confidence.
91, 68, 88, 72, 8580.8%Unstable. The 80.8% is nearly meaningless — a single split could have told you 91% or 68%.

Both rows average to roughly the same place. Only one of them is a result you should act on. Always report the standard deviation alongside the mean.

Wide spread usually means your dataset is too small, or the folds are not comparable — which brings us to the variants.

The variants you actually need

Stratified k-fold
Keeps each class in the same proportion in every fold. Use this by default for classification — otherwise a rare class can vanish from a fold entirely.
Group k-fold
Keeps all rows from the same source — one patient, one customer — in the same fold, so the model cannot recognise the individual instead of the pattern.
Time series split
Always trains on the past and tests on the future. Ordinary k-fold lets the model see tomorrow to predict today.

Leave-one-out takes k all the way to n — one row held out at a time. It squeezes the most from tiny datasets, but it costs n training runs and its estimates are noisy. Reach for it only when you have very few rows.

Choosing k

k = 5 or k = 10 are the standard choices, and the difference between them rarely matters. Higher k means more training data per round (so less pessimistic scores) but more compute. Start at 5, move to 10 if your dataset is small.

The mistake that invalidates cross-validation

⚠️ Preprocess inside the loop, not before it

If you scale your features across the whole dataset and then cross-validate, every fold’s mean and standard deviation were computed using data that fold was supposed to be tested on. The scores come back flattering and wrong.

The same applies to feature selection, imputing missing values, and anything else that learns from the data. All of it must happen inside each fold, fitted only on that round’s training portion. In scikit-learn, wrap the steps in a Pipeline and pass the pipeline to cross_val_score — it handles this correctly for you.

What cross-validation is for

Two jobs, and it is worth keeping them separate:

  1. Estimating performance — how well will this model do on data it has not seen?
  2. Comparing options — which model, or which hyperparameter setting, is best? This is what grid search does internally: cross-validate every candidate, keep the winner.

🧪 You still need a final test set

If you use cross-validation to choose between fifty candidate models, the winning score is optimistic — you picked the model that happened to suit those folds.

The clean approach is nested: hold out a true test set at the very start, cross-validate within the remaining data to make all your choices, then touch the held-out set once at the end.

🔑 Key Takeaways

  • Cross-validation trains k times, holding out a different fold each round.
  • Report the spread as well as the mean — a wide spread means the average cannot be trusted.
  • Use stratified folds for classification, group folds for repeated subjects, time-based folds for time series.
  • k = 5 or 10 is almost always fine.
  • All preprocessing must happen inside each fold, or the scores are inflated.

Further reading

scikit-learn’s cross-validation guide documents every splitter mentioned here, and its Pipeline documentation shows the pattern that prevents preprocessing leakage.

Where to go next

Scroll to Top