Machine Learning Slides 📂 Introduction · 5 of 17 50 min read

Cross-Validation in Machine Learning — K-Fold, Stratified, TimeSeries & Nested CV

A visual, beginner-friendly guide to Cross-Validation covering why single train-test splits lie, how K-Fold rotation works, when to reach for Stratified, Group, TimeSeries or Nested CV, choosing the right k, avoiding preprocessing and temporal leakage with sklearn Pipelines, computing honest confidence intervals, and eight golden rules every practitioner must follow before reporting any model score.

🔄

Cross-Validation

The resampling technique that turns a lucky-split gamble into a statistically honest performance estimate — K-Fold, Stratified, Group, TimeSeries and Nested CV, with the pitfalls that quietly ruin production models.
K-Fold Rotation Stratification Time-Series Split Nested CV

Press Next → or use ← → arrow keys

Section 01

What is Cross-Validation, And Why Do We Bother?

One coin flip doesn't tell you if the coin is fair
A single 80/20 train-test split is one roll of the dice. On the same 1,000-sample dataset, one random seed might report 78% accuracy, another 85%, another 91%. Same model, three very different answers.

Cross-Validation rotates the test set through the data multiple times, then averages the results — giving you a stable estimate with a real error bar instead of one lucky (or unlucky) number.
💡
The Three Problems CV Solves

Overfitting detection — exposes the gap between "great on training" and "grim on new data". Lucky splits — averages away the randomness of any single partition. Data utilisation — every sample gets to be tested exactly once, every sample trains k−1 times.

kRotations of the test fold
5Default k · industry standard
±σReport mean AND std
2–5%Inflation from data leakage
Section 02

K-Fold — The Rotating Test Set

Fold 1 Fold 2 Fold 3 Fold 4 Fold 5 Score Iter 1 0.86 Iter 2 0.84 Iter 3 0.88 Iter 4 0.85 Iter 5 0.87 Mean = 0.86 · Std = 0.015 · 95% CI ≈ [0.83, 0.89] Test Train
🔄
Every Sample Tested Exactly Once

Shuffle N samples, split into k folds. On each of k iterations, one fold is held out as test — the other k−1 train the model. Report mean ± std across all k scores. A high std is a red flag: your model behaves inconsistently across data slices.

Section 03

The Family — Six CV Methods You Should Know

🔄
Standard K-Fold
Shuffle, split into k folds, rotate the test fold. Default choice for regression & balanced classification.
⚖️
Stratified K-Fold
Locks class proportions inside every fold. Always use for classification — zero downside.
🎯
Leave-One-Out (LOOCV)
k = N. Every sample tested once alone. Maximal training data, prohibitive compute — tiny datasets only.
👥
Group K-Fold
Keeps related samples (same patient/user/session) inside one fold. Prevents catastrophic group leakage.
⏱️
TimeSeries Split
Expanding window — train on past, test on future. Non-negotiable for any temporally-ordered data.
🔁
Repeated K-Fold
Run k-fold R times with different seeds. Tightens the confidence interval for statistical comparisons.
🧭
The Decision Rule In One Line

Classification → Stratified. Grouped samples → GroupKFold. Time-ordered → TimeSeriesSplit. Everything else → k=5 standard. Anything else is a special case.

Section 04

Stratified K-Fold — Why It's The Default for Classification

Standard K-Fold random shuffle · class ratio wobbles Fold 1 6% Fold 2 14% Fold 3 8% Fold 4 12% Fold 5 10% ⚠ ratio swings 6% – 14% Stratified K-Fold locked at 10% in every fold Fold 1 10% Fold 2 10% Fold 3 10% Fold 4 10% Fold 5 10% ✓ every fold identical
🎯
No Downside, Real Upside

Stratified K-Fold prevents random bad splits that would leave a fold with too few minority-class samples to learn from. Every fold gets exactly the same class ratio as the full dataset. StratifiedKFold is the default in sklearn's cross_val_score for classifiers — for good reason.

Section 05

TimeSeries Split — Never Train On The Future

Jan Feb Mar Apr May Jun Jul Aug Fold 1 TRAIN TEST Fold 2 TRAIN TEST Fold 3 TRAIN TEST Fold 4 TRAIN TEST time only moves forward · expanding training window
Shuffling Time Series Data Is A Silent Disaster

Standard K-Fold on time-ordered data lets the model train on future observations and predict the past — the exact opposite of production. CV will look brilliant; deployment will collapse. Use TimeSeriesSplit for anything sequential: stock prices, sales, weather, telemetry, logs.

Section 06

Group K-Fold — When Samples Come In Clusters

400 patients · 5 X-rays each = 2,000 scans Patient 1 🩻 🩻 🩻 🩻 🩻 TRAIN Patient 2 🩻 🩻 🩻 🩻 🩻 TRAIN Patient 3 🩻 🩻 🩻 🩻 🩻 TEST — ALL 5 Patient 4 🩻 🩻 🩻 🩻 🩻 TRAIN Patient 5 🩻 🩻 🩻 🩻 🩻 TRAIN RULE — one patient, one fold If Patient 3 is in test, all 5 of their scans are in test — none in train Standard K-Fold would leak: model would see Patient 3's other scans during training
👥
The Most Common Silent Leak In Applied ML

Same patient in train + test → optimistic scores by 10–30 points. Same customer's transactions. Same user's clicks. Same video's frames. If your samples cluster naturally, use GroupKFold. Identify the grouping structure before you pick a CV method.

Section 07

Nested CV — Honest Numbers When You Tune Hyperparameters

OUTER LOOP · 5 folds · honest evaluation outer training fold outer TEST → score reported inner fold 1 grid search inner fold 2 grid search inner fold 3 grid search INNER LOOP · 3 folds · hyperparameter tuning only best params → retrain → score outer test 5 outer × 3 inner × 50 param combos = 750 model fits but every reported number is bias-free
🔒
Why Non-Nested CV Overstates By 1–5%

If you pick hyperparameters by CV score, then report that same CV score, you've overfit to the folds themselves. Nested CV separates the two: inner loop picks params, outer loop evaluates — never contaminated by the search.

Section 08

Choosing K — The Bias–Variance–Compute Triangle

kTrain per foldBiasVarianceComputeBest For
k = 367%HighLowCheapVery large datasets, prototyping
k = 580%ModerateLow3× cheapDefault · 100–10,000 samples
k = 1090%LowMedium2× k=5Research · tight comparisons
k = N (LOOCV)~100%MinimalHighN fitsDatasets under 100 samples
🎚️
The One-Line Recipe

Start with k = 5. Move to k = 10 only when you need tighter CIs and can afford double the compute. Reach for LOOCV only when the dataset is genuinely tiny (< 100 samples). Never use k = 2.

Section 09

Preprocessing Leakage — The Silent Score Inflator

❌ WRONG · scaler outside CV 1. Scaler fits on FULL dataset 2. cross_val_score on scaled X score inflated by 2–5% · test stats leaked in ✅ RIGHT · Pipeline inside CV 1. Pipeline( Scaler , Model ) 2. cross_val_score(pipeline, X, y) scaler refits fresh on each training fold
# ❌ WRONG — leaks test-fold statistics into training
X_scaled = StandardScaler().fit_transform(X)              # fits on ALL data!
scores   = cross_val_score(model, X_scaled, y, cv=5)

# ✅ RIGHT — scaler refits on each training fold only
pipe   = Pipeline([('scaler', StandardScaler()), ('model', SVC())])
scores = cross_val_score(pipe, X, y, cv=5)
💧
Always Wrap Preprocessing In A Pipeline

Scaling, imputation, feature selection, target encoding — anything that learns from data — must sit inside a Pipeline. That way it only sees the current training fold and transforms the test fold blindly. Outside the pipeline, you leak.

Section 10

Implementation — The sklearn CV Toolkit

# ── Single metric ─────────────────────────────────
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.pipeline import Pipeline

skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(pipe, X, y, cv=skf, scoring='roc_auc')
print(f"AUC = {scores.mean():.3f} ± {scores.std():.3f}")

# ── Multi-metric with train scores & timing ──────
from sklearn.model_selection import cross_validate

results = cross_validate(
    pipe, X, y, cv=skf,
    scoring=['accuracy', 'f1', 'roc_auc'],
    return_train_score=True,
    n_jobs=-1,
)

# ── Nested CV — honest tuning + evaluation ───────
from sklearn.model_selection import GridSearchCV

inner = StratifiedKFold(n_splits=3, shuffle=True, random_state=1)
outer = StratifiedKFold(n_splits=5, shuffle=True, random_state=2)

grid   = GridSearchCV(pipe, param_grid, cv=inner, scoring='roc_auc')
nested = cross_val_score(grid, X, y, cv=outer, scoring='roc_auc')
print(f"Honest AUC = {nested.mean():.3f} ± {nested.std():.3f}")
Two Speed & Sanity Tips

Set n_jobs=-1 to parallelise across every CPU core. Set random_state on every splitter so folds are reproducible — mean ± std is worth reporting only if others can recreate exactly your split.

Section 11

The Decision Tree — Which CV Should You Use?

🧭 CROSS-VALIDATION SELECTOR
1
Time-ordered data?TimeSeriesSplit. Never shuffle. Stock prices, sales, telemetry, logs — anything with a timestamp.
2
Samples share a group?GroupKFold. Multiple scans per patient, transactions per customer, frames per video. Keep the group together.
3
Classification?StratifiedKFold. Preserves class ratios; zero downside.
4
Regression on i.i.d. data? → Standard KFold(n_splits=5, shuffle=True).
5
Tuning hyperparameters AND reporting performance? → Wrap it in Nested CV. Otherwise your reported score is inflated by 1–5%.
6
Comparing two close models statistically?RepeatedStratifiedKFold(5×10) for 50 scores and tight confidence intervals.
Section 12

Common Pitfalls — What Silently Breaks Your Numbers

💧
Preprocessing Leakage
outside the Pipeline
Scaling or imputing on the full dataset leaks test statistics. Score inflated 2–5%. Always wrap in Pipeline.
Temporal Leakage
shuffled time series
Standard K-Fold on sequential data lets the model train on the future. Use TimeSeriesSplit. Non-negotiable.
👥
Group Leakage
same patient in both sets
Same subject in train + test → catastrophically optimistic scores. Identify grouping structure first.
🔁
Fold Overfitting
tune + report same score
Selecting hyperparameters by CV score then reporting that score = double-dipping. Use Nested CV.
📊
Ignoring Std
mean without variance
Mean 85% ± std 8% is risky — could be 77% or 93% in production. Always report both, or a 95% CI.
🚀
Deploying A Fold Model
shipping "fold 3's model"
Fold models trained on only (k−1)/k of the data. After CV confirms quality, retrain on 100% for production.
Section 13 · Part 1

Golden Rules — 1 to 4

🔄 CROSS-VALIDATION DISCIPLINE · RULES 1–4
1
Always use StratifiedKFold for classification. It's strictly better than standard K-Fold with zero downside — every fold gets the same class ratio.
2
Always wrap preprocessing in a Pipeline. Anything that learns from data (scaler, imputer, encoder) inside a Pipeline. Anything outside leaks.
3
CV is for evaluation. Retrain on 100% for deployment. The k fold-models are diagnostic artefacts. Your production model is trained on all your data.
4
Report mean ± std, not just mean. High variance across folds is a risk signal — flag it and investigate before shipping.
Section 13 · Part 2

Golden Rules — 5 to 8

🔄 CROSS-VALIDATION DISCIPLINE · RULES 5–8
5
Identify grouping structure BEFORE choosing CV. Multiple scans per patient? GroupKFold. Time-ordered? TimeSeriesSplit. Get this wrong and every metric downstream lies.
6
k = 5 is almost always right. Use k = 10 for tighter CIs when compute allows. LOOCV only for tiny (< 100) datasets. Never k = 2.
7
Use Nested CV when tuning and evaluating together. Otherwise you overfit to the CV folds and report scores 1–5% higher than reality.
8
Never touch the holdout test set until the very end. CV is your development sandbox. The holdout is a one-shot final exam — if you peek, tweak and re-peek, the test set has become part of training.
FINAL

CV — Turning A Lucky Number Into An Honest One

6CV methods to know
k = 5The default choice
±σAlways report variance
NestedFor tuning + reporting
PipelineNo leakage · every time
8Golden rules
🎯
The Foundation Is Set

You now understand how K-Fold rotates, why stratification matters, how time-series and grouped data demand different splitters, and why Nested CV is the gold standard when tuning. Every honest ML performance number you produce from now on rides on these ideas.

📚
Where To Go Next

Study hyperparameter tuning (GridSearch, RandomSearch, Optuna), then Learning Curves to diagnose bias vs variance, then bootstrapping for tighter CIs. Practice by re-running any past Kaggle notebook with proper Pipeline + Nested CV — the honest scores will humble you.

🔄 End of tutorial · Press to review, or click Restart