Model Evaluation with Cross-Validation
A workflow is a chain of stages where each stage passes its output to the next. The model is only the last link.
Try it: K-Fold Cross-Validation and Model Selection
How hold-out and k-fold cross-validation choose among candidate models: each fold takes a turn as the validation set, the fold errors are averaged, the lowest average picks the model, and only then is the untouched test set used once — while tuning on the test set would report an optimistic number.
How it works
- Set 10 test points aside; they take no part in any choice.
- Optionally shuffle the 20 development points (seeded), then cut them into k folds (hold-out: one chunk validates, the rest trains).
- For every round, train each candidate polynomial on the other folds and measure its validation MSE on the held-out fold.
- Average each candidate's fold errors (with repeated shuffling: average the p run scores; p × k fits per candidate).
- Select the candidate with the lowest average, retrain it on all development points, and evaluate it once on the test set.
- For contrast, show which candidate the test set itself would have picked — that figure is leaked and optimistic.
Default run (12 steps): 20 development points (sorted by x as they arrived) and 10 test points set aside. Candidates: polynomial degree 0, 1, 2, 3, 4, 5, 6. Plan: 5-fold cross-validation, shuffled with seed 1 → 5 fits per candidate (p × k = 1 × 5), 35 in total. … 5-fold cross-validation picks degree 3 (score 0.0768); its honest test MSE is 0.0889. Picking by test error would report degree 4 at 0.0868 — a leaked, optimistic figure.
Simplified: One fixed toy dataset (20 development + 10 test points from sin(2πx) with noise) and polynomial least squares of degree 0–6 as the candidate models. Shuffling uses a seeded mulberry32 Fisher–Yates; folds are contiguous chunks like scikit-learn's KFold. Hold-out uses the first of k chunks as the validation set.
Loading the simulation…
The Single-Model Picture Is Incomplete
A very common first picture of machine learning is a single model that receives data and returns predictions. In that picture the model is the whole workflow. Once you have chosen a good model, it seems the remaining work is simply feeding it numbers. This belief feels reasonable, and it is exactly the misconception this article corrects.
Before reading on, imagine a workflow in which you prepare the training data with one transformation, fit the model, and then send new test data to the model without applying that same transformation. What do you expect would happen to the test results?
Hints
- Think about whether the model was trained on numbers that had been transformed.
- Ask whether the new test numbers are on the same scale as the numbers the model learned from.
Why Real Workflows Are Chains of Steps
Real-world machine learning rarely involves an isolated use of a model. Instead, it is a sequence of processing steps. Data is typically gathered, transformed, and shaped into useful inputs, and only then given to a model. Each stage depends on the one before it, so the workflow is a chain rather than a single action.
Three kinds of stages commonly appear in these chains: feature extraction, preprocessing, and models. Choosing the right combination of these stages is somewhat of an art and often requires trial and error. Because of this, the chain itself is the unit you need to manage, not just the model at its end.
A workflow is a chain of stages where each stage passes its output to the next. The model is only the last link.
Tracing Data Through a Pipeline
The diagram below shows the general shape of a two-step chain: a scaling step (a preprocessing transformer) followed by a classifier (the model). Read it from left to right and notice that each stage receives the output of the stage before it. The tracing becomes concrete once you follow the training data through a fit call and then the test data through a predict call.
During fitting, the scaler sees the training inputs first, learns what it needs in order to transform them, and passes the transformed values forward. The classifier then fits on those transformed values, not on the raw inputs. During prediction, the new data goes through the same scaler and is then passed to the classifier. The scaler is not learned again at that point; it reuses what it learned during fitting.
The Pipeline Object and Its Interface
A pipeline chains several processing steps, such as feature extraction and preprocessing, into a single object that follows the fit, predict, and transform interface.
The value of this design is that a whole chain of work becomes one thing. Your code no longer has to remember each stage separately. The pipeline holds the transformers and the final estimator together, and it exposes methods that you already use on individual steps.
Building a Two-Step Pipeline in Python
The example below is an original illustration, not taken from the source. It chains a scaling step with a classifier. The scaler is the preprocessing step and the classifier is the model. It assumes X_train, y_train, and X_test already exist as your training inputs, training labels, and test inputs. The imports come from scikit-learn, the library that provides these classes.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
pipe = Pipeline(steps=[
("scaler", StandardScaler()),
("classifier", LogisticRegression()),
])
pipe.fit(X_train, y_train)
predictions = pipe.predict(X_test)- 1The three imports bring in the Pipeline class, the scaler, and the classifier.
- 2The Pipeline receives a list of (name, object) pairs. Order in this list is the order in which data flows.
- 3
pipe.fit(X_train, y_train)fits the scaler on the training inputs, transforms them, then fits the classifier on the transformed values. - 4
pipe.predict(X_test)transforms the test inputs with the already fitted scaler and then asks the classifier for predictions.
- The Pipeline is built from a list of named steps, applied in order.
- The scaler is a transformer; the classifier is the final estimator.
Tracing one fit call and one predict call
Given the pipeline above, what work happens when fit is called, and what work happens when predict is called on new data?
- 1Fit the scaler
The scaler receives X_train and learns the statistics it needs to transform data.
- 2Transform the training inputs
The scaler transforms X_train, producing scaled training inputs.
- 3Fit the classifier
The classifier fits on the scaled training inputs together with
y_train. - 4Transform the test inputs
On predict, the already fitted scaler transforms X_test. It does not learn anything new from the test data.
- 5Predict
The classifier receives the scaled test inputs and returns predictions.
The training data is used to learn both the scaling and the classifier, and the test data is only transformed and then predicted on.
Mistakes Pipelines Help Prevent
Compare the pipeline with a hand-built workflow. Without a pipeline, you would fit the scaler on the training data, transform the training data, fit the classifier, and then separately transform the test data with the scaler before calling predict on the classifier. Every one of those separate lines is a chance to skip a step or run them out of order. The pipeline removes that bookkeeping, which reduces the likelihood of these mistakes and keeps the code more succinct.
Common mistake Forgetting to apply the transformer to the test set
What it looks likeThe model is trained on scaled training inputs, but predict is called on raw test inputs.
Why it failsThe model has learned from numbers on one scale and is asked to predict from numbers on another scale, so the predictions are not based on consistent inputs.
Do this insteadKeep the scaler inside the pipeline so that predict automatically transforms the test inputs with the same fitted scaler.
Common mistake Applying steps in the wrong order
What it looks likeThe classifier is fitted on raw inputs, and the scaler is applied afterward.
Why it failsEach stage is meant to receive the output of the stage before it. Reversing the order means the model does not see the data it was designed to learn from.
Do this insteadList the steps in the order data should flow, and let the pipeline run them in that order.
Leakage Across Cross-Validation Folds
Cross-validation evaluates a workflow by repeatedly fitting and testing it on different portions of the data. This is why the steps must live inside the pipeline. If a preprocessing step is fitted once on the full dataset before cross-validation begins, the statistics it learns include rows that will later serve as validation data. The validation data has then already influenced the transformation, and the evaluation becomes misleading. The source states that if some processing steps sit outside the pipeline, they may not be handled consistently across the repeated fits and tests, and the evaluation can then be misleading.
In the right-hand arrangement, the scaler is part of the pipeline. Each time cross-validation fits the workflow, the scaler is fitted only on that iteration's training folds, and the held-out fold is only transformed. The validation rows never shape the statistics used for their own evaluation.
How Cross-Validation Refits the Whole Chain
In cross-validation, the data is divided into folds. In each iteration, one fold is held out as validation data and the remaining folds are used for training. The whole pipeline is then refit from scratch on the training portion, and its predictions are scored on the held-out fold. Repeating this for every fold gives one score per iteration, and those scores can be combined into an overall estimate.
- The pipeline object itself is passed in, not a fitted scaler or a fitted classifier.
- cv=5 requests five folds, each serving once as validation data.
Passing the pipeline itself to the evaluation function is what makes the scaling correct in every fold. The evaluation function can fit the whole chain on each training portion, so every transformer is learned only from data the model is allowed to see.
Grid Search Repeats the Same Chain
Grid search is described in the source as parameter selection: it tries combinations of settings and compares them. Each combination can be evaluated with cross-validation, which means each combination causes repeated fits and tests of the workflow. The source places special emphasis on this case because the repeated fits multiply any inconsistency. If a processing step sits outside the pipeline, it may be handled differently across these repeated fits, and the comparison between parameter settings becomes unreliable.
Capture every processing step inside the pipeline before running cross-validation or grid search. Then experiments change the contents of the chain while the way you use it stays the same. You can swap one step for another and evaluate the whole workflow again without rewriting the surrounding code.
Practice: Tracing a Pipeline
A colleague writes the following workflow: they fit a scaler on the full dataset, then run cross-validation on a classifier using the already scaled data. Explain whether this evaluation is trustworthy, and rewrite the workflow so that the scaler is placed correctly.
Hints
- Ask which rows influenced the scaler before the validation folds were held out.
- A single Pipeline containing the scaler and classifier passed to
cross_val_scoreavoids the problem.
Key Takeaways
- Real machine learning workflows are chains of processing steps, so the chain itself is the unit to manage rather than the model alone.
- A Pipeline holds named steps in order and follows the fit, predict, and transform interface, so the whole chain can be used as one object.
- Pipelines help prevent forgetting transformers on the test set and applying steps in the wrong order.
- Cross-validation and grid search refit the workflow repeatedly, so keeping every processing step inside the pipeline is essential for a proper evaluation.