Machine Learning ยท easy

What is cross-validation and why use k-fold?

Asked in Data Scientist interviews, in the Machine Learning round.

Short answer

Split data into k folds to estimate generalization robustly and use all data for validation.

How to answer it

Definition

Split the data into k parts, train on k minus one of them and validate on the held-out part, rotate through all k, and average the scores. Every row is used for validation exactly once and for training k minus one times.

Why not a single split

A single train-test split gives one estimate from one arbitrary partition. On a small dataset that estimate has high variance: a lucky split flatters the model and an unlucky one condemns it. K-fold averages over k splits, which both reduces that variance and uses all the data.

Example

from sklearn.model_selection import cross_val_score, StratifiedKFold

cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
scores = cross_val_score(model, X, y, cv=cv, scoring="roc_auc")
print(scores.mean().round(3), scores.std().round(3))

Output

0.842 0.011      the mean is the estimate,
                 the spread tells you how much to trust it

The standard deviation matters as much as the mean. A model scoring 0.84 plus or minus 0.01 is a different proposition from 0.84 plus or minus 0.09.

Choosing the variant

StratifiedKFold     classification: keeps the class balance in every fold
TimeSeriesSplit     temporal data: always train on the past, test on the future
GroupKFold          repeated units: keep one user entirely in one fold

Plain KFold on time series or on grouped data is a leak, not a choice.

Key points

FAQ

The 30-second answer

Split the data into k folds, train on all but one and validate on the one left out, rotate through all of them, then average. Every row gets used for validation exactly once.
The reason to prefer it over a single split is variance. One split gives one estimate from one arbitrary partition, and on a smallish dataset that number moves a lot with the luck of the split. Averaging over five or ten folds gives a more stable estimate and uses all the data.
The mistake I would watch for is fitting preprocessing outside the loop. Scaling or imputing on the whole dataset before splitting leaks the validation set into training. And for time series I would use TimeSeriesSplit rather than shuffling, because training on the future to predict the past makes any model look excellent.

In the interview

Practice this for real