Worked examples — Cross-validation — k-fold
Before anything, three plain-word reminders so no symbol here is unearned:
Recall What do
and mean again? ::: the total number of samples (rows) in your dataset. ::: the number of folds — how many equal piles we cut the data into. One fold ::: one of those piles, used once as the test set while the other piles train the model.
Recall What is a "score" and why do we average?
Score of one fold ::: a single number (accuracy, F1, RMSE…) telling how well the model did on that held-out pile. Why average the scores ::: one split can get lucky or unlucky; the mean of splits is a steadier estimate of true performance.
The two metrics we will actually score with
Every fold's "score" on this page is one of two numbers. Define them once, here, so nothing below is borrowed on faith.
The scenario matrix
Every k-fold problem is a combination of the axes below. Each cell is a distinct thing that can go wrong or behave differently — so each gets its own worked example.
| Cell | Case class | What makes it special | Covered by |
|---|---|---|---|
| A | Clean, balanced, divisible by | The textbook case, every fold identical size | Example 1 |
| B | not divisible by (remainder) | Folds have unequal sizes — how are leftovers spread? | Example 2 |
| C | Degenerate small: (LOOCV limit) | Test fold has one sample; score is 0 or 1 | Example 3 |
| D | Degenerate small: | Only two folds — closest to a single split | Example 4 |
| E | Imbalanced classes (rare event) | Random folds distort class ratio → stratify | Example 5 |
| F | Regression metric (RMSE) not accuracy | Averaging error, not "correctness"; units matter | Example 6 |
| G | Time-ordered data (leakage trap) | Shuffling steals the future → forward-chaining | Example 7 |
| H | Exam twist: variance vs mean judgement | Two models, same mean, different std — which wins? | Example 8 |
Example 1 — Cell A: the clean divisible case
Forecast: guess the mean before reading on — is it above or below ?
The figure below shows the rotation: each row is one of the five folds, blue cells are the 8 training samples, and the single orange block of 2 cells is that fold's test set. Trace down the rows and you can see the orange block slide left-to-right — every sample lands in the test set exactly once, and each row's per-fold accuracy is printed on the right.

- Find fold size. . Each fold holds exactly 2 samples (one orange block in the figure), each model trains on the other 8 (the blue cells). Why this step? We must confirm folds are equal — Cell A only holds when divides evenly by .
- Average the scores (the CV score). Why this step? The parent formula — averaging is what turns 5 lucky/unlucky numbers into one estimate.
- Spread across folds (sample standard deviation). The squared deviations are , summing to . Divide by : . Square root: . Why this step? We divide by , not , because the mean itself was estimated from the same data — one degree of freedom is "used up". This is the sample standard deviation.
Forecast check: you were asked to guess if the mean beats . It does — . The eyeball intuition works because three of the five scores () sit above and only pull the average up; that "count how many are above the line" trick is the mental shortcut the forecast was training.
Verify: the five scores lie in ; a mean of sits inside that range ✓. Total split into 5 equal shares of ✓.
Example 2 — Cell B: not divisible by
Forecast: — you cannot have samples in a fold. So what happens to the leftover?
The figure below lays the 23 samples out as five coloured bars. Notice the first three bars are one cell longer than the last two: that extra cell is the remainder being handed out, one per fold, to the earliest folds. The caption confirms the sizes add back to .

- Split the remainder. . The base size is ; the remainder is spread one-per-fold to the first three folds (the three longer bars). Fold sizes: .
Why this step? scikit-learn's
KFoldgives the firstn % kfolds one extra sample so every sample is used exactly once and no fold is empty. Sizes stay "approximately equal", matching . - Check total. ✓ — every sample is tested once, none twice. Why this step? The defining guarantee of k-fold is every point tests exactly once; unequal folds must still sum to .
- Average the RMSEs. Why this step? RMSE is a per-fold number (defined above as ); the CV estimate is still their mean.
Forecast check: your instinct that can't be a fold size was right — the fix is not rounding but distributing the leftover samples, giving the mixed sizes . The number to remember is n % k: it counts exactly how many folds get the bonus sample.
Verify: sizes sum to ✓. Mean lies between min and max ✓. Units stay kg (we averaged kg values) ✓.
Example 3 — Cell C: the LOOCV limit
Forecast: with only one test point per fold, what values can a single fold's accuracy take?
- Each test fold has one sample. . Train on , test on . Why this step? This is the extreme named in the parent as LOOCV.
- Each fold score is 0 or 1. One sample is either right () or wrong () — no in-between. Scores: . Why this step? accuracy . This is why LOOCV fold scores are high variance / noisy — each is a coin-flip-like or .
- Average. Why this step? The mean of the scores equals the overall fraction correct — exactly of .
Forecast check: the answer to the prompt is "only or " — a single test point can only be fully right or fully wrong. That is exactly why the average () is the informative number in LOOCV while any single fold's score is almost useless on its own.
Verify: correct out of total ✓. Every value averaged was or , confirming the single-sample test folds ✓.
Example 4 — Cell D: the two-fold extreme
Forecast: with only 2 folds, how much of the data trains each model?
- Fold size and training fraction. . Each model trains on fold samples of data. Why this step? Small means each model sees less training data — here only half — so each score is a pessimistic (higher-bias) estimate of the full-data model.
- Average. Why this step? Same averaging rule; two folds still each test once (). Each F1 here is the balanced precision–recall blend defined at the top.
- Interpret the tie to a single split. With , fold 1 trains on fold 2 and vice-versa: it is two mirror-image train/test splits. Averaging them is barely more robust than one split — that is why we prefer or .
Forecast check: the answer to "how much trains each model?" is exactly half (). That low training fraction is the whole reason is biased-pessimistic — the model is judged while starved of data it would have in production.
Verify: ✓. Mean ✓.
Example 5 — Cell E: rare event → stratified k-fold
Forecast: with failures split into folds, how many failures should each fold hold on average?
The figure contrasts the two strategies as bar charts of "failures per fold". On the left (random k-fold) the bars are jagged — one fold is red at height , meaning it caught no failures at all. On the right (stratified) all four bars sit flat at the target height of , matching the rate. The dashed grey line marks that target of .

- True class rate. failures. Why this step? This baseline is what each fold should mirror. The full dataset ratio is the target for stratified sampling.
- Expected failures per fold. failures per fold on average (the dashed line in the figure). Why this step? If randomness deals a fold failures (the red bar), that fold has no positives to detect.
- Why the zero-failure fold's F1 collapses. F1 needs true positives (the in its formula above). With zero actual positives in the test fold, recall's denominator is → F1 is undefined (scikit-learn returns ). That fold's score is meaningless and drags/spikes the average. Why this step? Rare-event scoring is only valid if positives exist in every test fold.
- Stratified fix. Stratified k-fold forces each fold to hold failures — i.e. failures per fold (the flat right-hand chart), guaranteeing every fold can compute a real F1.
Forecast check: the "should be" number is 3 per fold, and that is precisely the value stratification enforces on every fold (the flat green bars). The random scheme's failure was that it deviated from this 3 — one fold got 0. Your forecast of 3 is the yardstick that exposes the random scheme as broken.
Verify: samples-per-fold failures/fold, and = total failures ✓. ✓.
Example 6 — Cell F: regression, RMSE units
Forecast: is the CV RMSE just the mean of these five, or do we have to square-and-root something?
- Average the fold RMSEs directly. Why this step? Each fold already is an RMSE (the from the definition above). The classic recipe averages the per-fold scores — we do not re-pool residuals. (Pooling residuals is a different, valid variant; the parent's formula uses the mean of scores.)
- Spread across folds. Deviations from : . Squares: , sum . Divide by : . Root: kg. Why this step? Same sample-std reasoning as Example 1 — one degree of freedom used by the mean.
- State units. Both mean and std are in kg (same units as the target), because RMSE inherits the target's units through that final square root. A "% accuracy" interpretation would be wrong here. Why this step? A metric's units decide how you may interpret and combine its values; treating a kg-error like a fractional accuracy would silently corrupt every downstream comparison.
Forecast check: the answer to "mean, or square-and-root?" is just the mean — because each fold value is already an RMSE (the squaring-and-rooting happened inside each fold). The trap the forecast guarded against is double-processing numbers that are already error summaries.
Verify: sum , mean ✓; std ✓; units kg ✓.
Example 7 — Cell G: time-ordered data, the leakage trap
Forecast: what is wrong with letting the model train on while testing on ?
The figure stacks the four forward-chaining folds as rows. In every row the blue cells (training past) sit strictly to the left of the single orange cell (the next-day test), and the grey cells are future days not yet available. The bottom arrow marks time flowing left-to-right — no orange test cell ever has a blue training cell to its right, which is exactly the "no future leaks backward" guarantee.

- Spot the leakage. Shuffled folds let a model train on future days () to predict a past day (). In deployment you never have the future, so shuffled CV over-estimates performance. Why this step? k-fold's fairness assumes each test fold is "unseen future"; time order breaks that assumption. This is the domain of time-series CV.
- Why shuffled must be abandoned, and what replaces it. We cannot keep the colleague's shuffled folds at all — shuffling is the very act that leaks the future. In time-series CV, is not chosen freely; it is derived from how many forward steps you take. We fix an initial training window (here the first days, needed to fit any model) and then advance one day at a time. With days and a window of , that yields forward folds — so effectively , and is dictated by the data length, not picked for convenience.
Why this step? It replaces the illegal shuffled splits with ordered ones and explains the change from the stated to folds: the fold count follows from
n − (initial window), not from a free choice. - Build forward-chaining folds. Always train on the past (blue cells), test on the next block (orange cell):
- train → test
- train → test
- train → test
- train → test Why this step? Every training set precedes its test point in time — no future leaks backward.
- Count test evaluations. Points tested: → test points. Unlike plain k-fold, forward chaining does not test every point: the first two days () only ever seed the earliest training window and are never themselves held out. So the "every sample tested exactly once" guarantee of ordinary k-fold is deliberately given up here in exchange for never peeking at the future. Why this step? Recognising that early samples are train-only is the whole point — it is the price time-series CV pays for realism.
Forecast check: the answer to "what's wrong with training on to predict ?" is that is the future relative to — in real deployment you would not yet have it, so the score is dishonestly inflated. The forward-chaining scheme is exactly the arrangement that makes such time-travel impossible.
Verify: with and initial train window , tested points ✓. Each training set is a strict prefix of indices, so max(train index) test index in every fold ✓.
Example 8 — Cell H: exam twist, mean vs variance
Forecast: identical means — so what breaks the tie?
- Confirm the means match. Why this step? The trap is assuming equal means ⇒ equal quality. They tie on average, so the mean alone cannot decide.
- Compute each spread (the fold-to-fold std). For P, deviations , squares sum , , root . For Q, deviations , squares sum , , root . Why this step? The variance across folds measures consistency — a safety-critical concern that the mean hides.
- Decide. . Deploy Model P: same expected F1 but far steadier across data subsets. Model Q's swing ( to ) means on some real flight populations it could fail badly. Why this step? In aerospace, predictable mediocrity beats erratic brilliance — a model that is occasionally excellent but sometimes poor is a safety liability.
Forecast check: the tie-breaker you were asked to name is the standard deviation — the second of the "always two numbers" pair. Equal means forced you to look past the average to consistency, which is the entire lesson of this exam-style cell.
Verify: both means ✓; , , and ✓.
Recall Which example covers which trap?
Unequal fold sizes ::: Example 2 (remainder spread to first n % k folds).
Single-sample test folds ::: Example 3 (LOOCV, scores are 0/1).
Rare event / stratification ::: Example 5.
Time leakage / forward chaining ::: Example 7 (only points tested).
Same mean, pick by std ::: Example 8.
Parent: Cross-validation — k-fold · Hinglish: 5.6.05 Cross-validation — k-fold (Hinglish)