Unit 6, lesson 37

Cross-Validation and Preprocessing Pipelines

How k-fold cross-validation scores a whole training procedure, how stratified, grouped and temporal folds match the data, and how a preprocessing pipeline refits every learned step in each fold to prevent fold leakage.

  • Video 37
  • Bias, Variance and Cross-Validation

A colleague standardizes every column of a table and then runs cross-validation on the standardized data. The scaler’s means and spreads were computed with the very rows each fold later holds out, so every fold score grades a procedure that has already seen part of its exam. This lesson defines k-fold cross-validation as an evaluation of a whole training procedure, preprocessing included, shows how to choose ordinary, stratified, grouped or temporal folds to match the data and the intended use, and puts every learned step inside a pipeline that is refitted in each fold.

Key terms

K-fold cross-validation

Definition Let the development data be the nn rows that remain after a test set has been set aside, and fix a training procedure, meaning every learned preprocessing step together with the model and its settings. Choose an integer kk with 2≤k≤n2 \le k \le n and partition the rows into kk disjoint nonempty folds V1,…,VkV_1, \dots, V_k. For each jj, fit the whole procedure on the training rows TjT_j, all rows outside VjV_j, and use the fitted result to predict the rows of VjV_j. If score⁡j\operatorname{score}_j is the score on fold jj, the cross-validation estimate is the mean of the fold scores,

CV⁡=1k∑j=1kscore⁡j.\operatorname{CV} = \frac{1}{k} \sum_{j=1}^{k} \operatorname{score}_j .

When the score is the average over the fold’s rows of a per-row quantity, such as squared error or correct classification, the size-weighted mean with weights ∣Vj∣/n\lvert V_j \rvert / n equals the average over all nn held-out predictions, and it agrees with the plain mean when the folds have equal sizes. For a metric that is not such an average, such as F1 or ROC AUC, the mean of fold scores and the metric computed once on the pooled held-out predictions can differ, and the pooled version mixes scores from different fitted models. Every row is predicted exactly once, by a model fitted without it. The estimate describes the procedure trained on about (k−1)/k(k - 1)/k of the development rows, not one fitted model, and after a procedure is chosen it is refitted on all development rows. The training sets overlap, so the fold scores are dependent, and their standard deviation divided by k\sqrt{k} is not automatically a valid standard error. Cross-validation compares and chooses procedures within the development data, and the test set stays outside it.

In plain words Every row takes one turn as unseen data, and the procedure is rebuilt from scratch for each turn, so no row ever grades a model that learned from it. The rotation uses all development rows for checking, but the result describes the procedure rebuilt on somewhat smaller training sets, not any single model.

Example Six constructed rows have inputs 0,1,2,8,9,100, 1, 2, 8, 9, 10 and labels 0,0,0,1,1,10, 0, 0, 1, 1, 1. Three folds hold out the inputs {0,8}\{0, 8\}, {1,9}\{1, 9\} and {2,10}\{2, 10\}, so each training set has 44 rows, two thirds of the data. Two procedures run on these same folds. One standardizes the input and then classifies by the label of the single nearest training input. The other standardizes and then fits a logistic regression with an L2 penalty, with the details under preprocessing pipeline below. Both classify all six held-out rows correctly, so both have cross-validated accuracy 11. Six rows of well-separated constructed data show the mechanics only. They cannot show that the two procedures will do equally well on new data.

Stratified folds

Definition For a classification target, stratified folds are folds in which each class makes up about the same share as in the whole development set, as closely as whole rows allow. A common construction splits the rows of each class into kk nearly equal parts and joins one part of every class into each fold. Stratification reduces the chance variation of class counts between folds, and when a class has at least kk rows it keeps that class from vanishing from a validation fold, where a metric such as recall could be undefined. For a numerical target the same idea can be applied to bins of the target. Stratification controls only the label proportions. It does not keep linked rows together, it does not respect time order, and it does not make dependent rows independent.

In plain words Deal the rows of each class around the folds like cards, so that every fold has roughly the class mix of the whole data set.

Example In the six-row example each fold holds one row of each class, the overall proportion 1/21/2. For a larger case, take 200200 rows with 1010 positives and five folds of 4040. If the folds are a random partition with all partitions equally likely, a given fold contains no positive with probability

(19040)(20040)≈0.101,\frac{\binom{190}{40}}{\binom{200}{40}} \approx 0.101,

and inclusion and exclusion over the five folds shows that at least one fold has no positive with probability about 0.4550.455. Stratified folds put exactly 22 positives in every fold.

Grouped folds

Definition Suppose each row belongs to a group, such as a customer, a patient, a machine or a measurement session, and the model will be used for groups it has not seen. Grouped folds assign whole groups to folds, so all rows of a group sit in the same fold and no group appears among both the training rows and the held-out rows of any split. Rows of one group are often more alike than rows of different groups, so a held-out row whose group also appears in training is usually easier to predict than a row from a new group, and ordinary row folds then tend to overstate performance for new groups. The number of groups, more than the number of rows, limits how much independent evidence the folds hold, and fold sizes can differ when groups differ in size. If the model will instead predict further rows of known groups, the folds should copy that use. Which units form the groups follows from how the model will be used and is settled before any scores are seen.

In plain words If the model will meet strangers, every person’s rows go into one fold together. Otherwise the evaluation quietly lets the model recognize people it has already met.

Example A table has 300300 customers with 44 orders each, 1,2001{,}200 rows in all, split into ordinary random folds of 240240 rows with all partitions equally likely. For a held-out order, the probability that the customer’s other 33 orders all land in the same fold is

239⋅238⋅2371199⋅1198⋅1197,\frac{239 \cdot 238 \cdot 237}{1199 \cdot 1198 \cdot 1197},

about 0.00780.0078, so with probability about 0.9920.992 at least one other order of the same customer is among the training rows. With grouped folds of 6060 customers each, that probability is 00.

Temporal folds

Definition Temporal folds evaluate a procedure the way it will be used, forward in time. The rows are ordered by prediction time, and each split trains on rows before a cutoff and validates on a later block, so every training row precedes every validation row. In an expanding window each later split also trains on the earlier validation blocks, and in a sliding window the training period keeps a fixed length. Every feature may use only information available at its own row’s prediction time, and a training label must already have been final when the model would have been trained. When targets or features are built over windows of time, a gap between the last training rows and the validation block keeps the same raw events from feeding both sides. Shuffled or stratified folds put later rows into the training data for earlier rows, and stratifying the labels does not repair that. Temporal fold scores describe how the procedure would have done at past cutoffs, and conditions can still change after the last one.

In plain words Train on the past and validate on the future, one cutoff at a time, using only what was known before each cutoff.

Example With 1212 months of data and an expanding window, three splits can train on months 11 to 66 and validate on months 77 and 88, train on months 11 to 88 and validate on months 99 and 1010, and train on months 11 to 1010 and validate on months 1111 and 1212. Suppose the target counts a customer’s purchases in the 3030 days after the prediction time. A training row dated in the last 3030 days before a cutoff then has a label that depends on purchases after the cutoff, inside the validation period, and that label was not yet final at the cutoff. Leaving out training rows from those 3030 days, a gap before each validation block, removes the overlap.

Preprocessing pipeline

Definition A preprocessing pipeline is an ordered chain of steps, such as an imputer, a scaler, an encoder or a feature selector, ending in an estimator. Each preprocessing step has a fit operation, which learns values from the rows it receives, and an apply operation, which maps rows using the stored values. Fitting the pipeline on rows TT fits the first step on TT, applies it to TT, fits the second step on that output, and so on, and finally fits the estimator. Predicting for new rows applies the stored steps in order and then the fitted estimator, without refitting anything. Cross-validating a pipeline fits a fresh copy of the whole chain on each set of training rows TjT_j, so every learned value comes from TjT_j alone. A step that learns nothing from data, such as the logarithm of a positive feature, is harmless outside the folds, and keeping it inside the pipeline costs nothing.

In plain words A pipeline treats preprocessing as part of the model. Whatever a step learns from data it learns from the training rows of the current fold, and the held-out rows are then processed the way new data will be.

Example In the first fold of the six-row example the training inputs are 1,2,9,101, 2, 9, 10. Their mean is 5.55.5, the squared deviations 20.25,12.25,12.25,20.2520.25, 12.25, 12.25, 20.25 add to 6565, and dividing by the 44 rows gives the variance 16.2516.25. The scaler stores the mean 5.55.5 and the standard deviation 16.25≈4.031\sqrt{16.25} \approx 4.031, and it maps the held-out inputs 00 and 88 to about −1.364-1.364 and 0.6200.620. The second and third folds store the means 55 and 4.54.5 with variances 1717 and 16.2516.25. In each fold the logistic regression minimizes the mean log loss on the scaled training inputs plus 0.1⋅w2/20.1 \cdot w^2/2, with the intercept unpenalized. The fitted slopes are about 1.6291.629, 1.6121.612 and 1.6291.629, and the fitted intercept is 00 in every fold, because each scaled training input with label 00 is matched by its negative with label 11. The held-out probabilities of class 11 are about 0.0980.098 and 0.7330.733 in the first fold, 0.1730.173 and 0.8270.827 in the second and 0.2670.267 and 0.9020.902 in the third, so the threshold 0.50.5 classifies all six rows correctly. In scikit-learn the comparison can be written as follows.

import numpy as np
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score

X = np.array([[0], [1], [2], [8], [9], [10]])
y = np.array([0, 0, 0, 1, 1, 1])
# (training rows, held-out rows) for each fold
folds = [
    ([1, 2, 4, 5], [0, 3]),
    ([0, 2, 3, 5], [1, 4]),
    ([0, 1, 3, 4], [2, 5]),
]

knn = make_pipeline(StandardScaler(), KNeighborsClassifier(n_neighbors=1))
# C = 1 / (4 rows * 0.1) gives the penalty 0.1 * w**2 / 2
# on the mean log loss; the intercept is not penalized
logit = make_pipeline(StandardScaler(), LogisticRegression(C=2.5))
for model in (knn, logit):
    print(cross_val_score(model, X, y, cv=folds).mean())

Fold leakage

Definition Fold leakage occurs when information from a fold’s held-out rows reaches the fitting of the model that is scored on those rows. Common routes are a preprocessing step fitted once on all development rows before the folds are formed, such as imputation values, scaling constants, category encodings, selected features or resampled rows, rows of one group or of a later period on both sides of a split, and hyperparameters chosen with the same folds whose scores are then reported. Under fold leakage the cross-validation score no longer evaluates the procedure that will run on new data, and it is usually optimistic. The size of the effect ranges from nothing to very large, depending on the step, the model and the data, so a small observed change does not excuse a leak. The repair is to place every learned step inside the pipeline, to choose folds that match the data, and to keep any tuning inside the training rows, as nested evaluation does.

In plain words Each fold is a rehearsal of meeting new data. Anything learned from the held-out rows before they are scored, even a mean or a list of chosen columns, spoils the rehearsal.

Example If the six inputs are standardized once with all rows, the scaler uses the mean 55 and the standard deviation 100/6≈4.082\sqrt{100/6} \approx 4.082, so in the first fold the input 00 becomes about −1.225-1.225 instead of −1.364-1.364, because the held-out inputs 00 and 88 helped set the scale. With a single feature this rescaling keeps the order of the inputs, so the nearest neighbors and the accuracies here do not change. That is a property of this example and not a reason to accept the leak. A sharper case is an identifier column in which every value occurs in exactly one row, encoded by the mean label of the rows that share the value. Computed on all rows, every row’s code equals its own label, so a threshold of 0.50.5 classifies every held-out row correctly whatever the labels are. Fitted inside each fold, every held-out identifier is unseen, receives the same fallback value, and carries no information.

Check yourself

  1. In the second fold of the six-row example the training inputs are 0,2,8,100, 2, 8, 10 with labels 0,0,1,10, 0, 1, 1, and the held-out inputs are 11 and 99. Find the stored mean and standard deviation, dividing by the number of training rows, the scaled held-out inputs, and the labels predicted by the one-nearest-neighbor model.
Show the answer

The mean is 20/4=520/4 = 5. The deviations −5,−3,3,5-5, -3, 3, 5 have squares 25,9,9,2525, 9, 9, 25 that add to 6868, so the variance is 68/4=1768/4 = 17 and the standard deviation is 17≈4.123\sqrt{17} \approx 4.123.

The scaled training inputs are about −1.213-1.213, −0.728-0.728, 0.7280.728 and 1.2131.213. The held-out input 11 maps to −4/17≈−0.970-4/\sqrt{17} \approx -0.970 and the input 99 maps to 4/17≈0.9704/\sqrt{17} \approx 0.970.

The scaled input −0.970-0.970 lies about 0.2430.243 from both −1.213-1.213 and −0.728-0.728, so the inputs 00 and 22 tie as nearest neighbors. Both have label 00, so the prediction is 00 under any tie rule, which is correct. In the same way 0.9700.970 ties between the inputs 88 and 1010, both with label 11, and the prediction 11 is correct. Standardizing a single feature shifts it and multiplies it by a positive number, which keeps every distance comparison, so these are the same ties as on the original scale.

  1. A colleague standardizes all 120120 development rows and then runs six-fold cross-validation on the standardized table, with 2020 rows in each validation fold. Which rows influenced the scaling used in each fold, and how should the workflow be repaired? How many rows do two different training sets share, and what does that mean for the six fold scores?
Show the answer

The global mean and standard deviation came from all 120120 rows, so in every fold the 2020 rows being scored helped set the scale applied to them. That is fold leakage.

The repair fits a fresh scaler in each fold on that fold’s 100100 training rows only and applies the stored mean and standard deviation to the 2020 held-out rows. The same holds for every other learned step, such as imputation, encoding or feature selection, which is easiest to guarantee by cross-validating a pipeline that contains them all.

Two different training sets share 120−20−20=80120 - 20 - 20 = 80 rows, and every row belongs to the training sets of five of the six folds. The fitted models are therefore similar and their scores are correlated, so the six scores are not six independent experiments. Report the fold design, the mean score and the spread between folds as a description, not as a confidence interval. After the procedure is chosen, refit it on all 120120 development rows and evaluate it once on the untouched test set.

  1. A colleague proposes stratified five-fold cross-validation for each of three projects. In the first, 5,0005{,}000 loan applications from different applicants, of which 33 percent defaulted, can be treated as independent draws from the population the model will serve. In the second, 2,4002{,}400 clinic visits come from 400400 patients and the model will be used for new patients. In the third, three years of daily sales are used to forecast next week’s sales. Is the proposal right for each, and what should replace it where it is not?
Show the answer

For the loan applications it fits. With 1,0001{,}000 rows per fold and 150150 defaults in all, stratified folds hold exactly 3030 defaults each, so no fold is left with too few defaults to score recall or precision.

For the clinic visits it is not enough. Stratification balances the labels but leaves visits of one patient spread over several folds, so the model is scored on patients it has partly seen. Use grouped folds that keep each patient’s visits together. If the classes are unbalanced, the folds can also be balanced as far as whole patients allow, but the grouping comes first.

For the sales forecast it is wrong. Stratified or shuffled folds would train on later days to predict earlier ones. Use temporal folds that train on the days before each cutoff and validate on the following week, build every lagged feature only from sales before the prediction time, and leave a gap whenever a feature or target window would otherwise cross the cutoff. In all three cases the prediction time and the unit of future use are defined first, and the folds are chosen to copy them.

How this lesson connects