← All Posts
Deep Learning · Data Preparation and Preprocessing · Splitting & Stratification

Hold-Out vs Cross-Validation

You have enough data to train two candidate models, but only one small validation set. Model A wins today. Would it still win if a few different examples had been reserved for validation? That is the practical reason to consider cross-validation.

A hold-out evaluates candidates on one fixed reserved subset. Cross-validation repeats fitting and evaluation with several training/validation partitions. The choice changes how development data are used and how many fits are needed. It does not change the need for a suitable boundary or an independent final assessment.

Separate model selection from final evaluation first

Suppose we have 1,000 independent examples. Reserve 100 for a final test and use 900 for development. The decision in this chapter concerns those 900 development rows. We can divide them once, or rotate which development rows validate each fit. The final 100 stay outside both procedures.

Cross-validation libraries often call a fold’s held-out rows “test.” If we use their scores to choose a model, those rows serve the validation role. The three-set chapter explains why a name in an API does not determine whether an assessment is independent.

One hold-out versus three rotating folds

Divide the development data into three blocks of 300 rows, A, B, and C. A single hold-out might train on B and C and validate on A. Three-fold cross-validation adds the other two possible held-out blocks:

Round 1Block AvalidateBlock BtrainBlock Ctrain
Round 2Block AtrainBlock BvalidateBlock Ctrain
Round 3Block AtrainBlock BtrainBlock Cvalidate
Fit a fresh pipeline in every round. Each fit uses 600 rows and is validated on 300. Every development row validates one fit and trains two others. The separate 100-row final test does not appear in this diagram.

A validation row may be training data in a different round. That is expected. What matters is that its own validation prediction comes from a fit that did not use it. Carrying a fitted scaler or classifier from one round into the next would break this separation.

The ranking can depend on the held-out block

These illustrative accuracies show why looking beyond one split can help:

CandidateValidate AValidate BValidate CMean
Model A82%78%80%80%
Model B80%82%81%81%

On the first hold-out, Model A wins by two percentage points. Across the three rounds, Model B has the higher mean. Its calculation is simply $(80+82+81)/3=81\%$. The mean describes performance across these validation fits; it is not the accuracy of a single model trained on all 900 rows.

Every candidate must use the same folds for this comparison. Otherwise, a difference in scores might reflect a difference in evaluation examples. A one-point average advantage also does not establish that Model B is reliably better. Consider the size and consistency of differences, evaluation sample size, training cost, and the needs of the application.

Should we average fold scores or pool predictions?

For accuracy with equally sized folds, the two agree: averaging the three fractions correct is equivalent to counting correct held-out predictions across all 900 rows. With unequal fold sizes, an unweighted fold mean gives small folds more influence per row.

For nonlinear metrics such as F1 or AUC, averaging fold scores need not equal computing a metric on pooled predictions. AUC comparisons across predictions from different fitted models can introduce additional interpretation problems. State the aggregation rule and choose it for the metric and evaluation unit.

Compare the cost at the same training size

In this example, one hold-out needs one 600-row fit per candidate. Three-fold CV needs three 600-row fits per candidate. For two candidates, that is two versus six development fits. After selection, fitting the chosen recipe on all 900 development rows adds one more fit.

A larger number of folds uses a larger fraction of the development data in each fit, but also requires more fits. It is not a free route to a more reliable result. For expensive models or large datasets, one well-designed validation block may already provide enough evidence. For small datasets, rotating folds can make better use of limited examples.

SituationReasonable starting designReason
Large development set; expensive fitsOne substantial validation hold-outEnough evaluation examples may be available without repeated fitting.
Limited independent examples; affordable fitsA small number of cross-validation foldsEvery example can help train some fits and validate another.
Unseen users, devices, or documentsGroup hold-out or group CVThe unfamiliar unit must remain separated in every fit.
Future predictionsLater validation blocks or rolling-origin evaluationTraining must respect chronology and label availability.

Decide between group, time, and ordinary row boundaries before choosing the number of folds. Repeating an invalid split can make the wrong answer look more stable.

Keep preprocessing inside the search

The runnable example below uses a separate synthetic classification dataset. It evaluates three regularization strengths for logistic regression with three-fold validation. Smaller C means stronger regularization; the point here is the evaluation structure, not a claim about which value is best in general.

from sklearn.datasets import make_classification
from sklearn.model_selection import (
    GridSearchCV, StratifiedKFold, train_test_split
)
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

X, y = make_classification(n_samples=1000, random_state=9)
X_dev, X_test, y_dev, y_test = train_test_split(
    X, y, test_size=100, random_state=42, stratify=y
)
cv = StratifiedKFold(n_splits=3, shuffle=True, random_state=43)
pipeline = make_pipeline(
    StandardScaler(), LogisticRegression(max_iter=1000)
)
search = GridSearchCV(
    pipeline, {"logisticregression__C": [0.1, 1.0, 10.0]},
    cv=cv, scoring="accuracy", refit=True
)
search.fit(X_dev, y_dev)
print("Chosen setting:", search.best_params_)
print("Development CV accuracy:", search.best_score_)

# Final evaluation after the search and refit are complete.
print("Final test accuracy:", search.score(X_test, y_test))

There are nine validation fits—three settings times three folds—plus one refit on all 900 development rows. Each fit learns its own scaler from its training portion. The chosen refitted pipeline is what search.score evaluates on the final 100 rows. GridSearchCV’s documentation describes these search and refit roles.

Cross-validation still participates in selection

The best CV score was chosen because it was the largest among the candidates. It can therefore be optimistic about the selected procedure, especially after a large or adaptive search. Cross-validation does not make the winning development score independent of model selection.

Use the reserved final test to assess the chosen refitted system. When the aim is to assess an entire tuning procedure without relying on one final hold-out, nested cross-validation uses an outer held-out loop and performs the full search inside each outer training partition. The nested-CV example illustrates the distinction.

Do not read overlapping fold scores as independent experiments: their training sets share data. Report the folds and aggregation honestly. If the comparison remains inconclusive, better evaluation data can be more valuable than adding more repeats of nearly the same data.

Continue to the cross-validation series for the detailed fold algorithms. This splitting series’s overview brings the design choices together before the next preprocessing stage.

References and further reading