Who Checks the Model-Choosing Process?
Trying enough settings can produce an attractive validation score by chance. Put the search inside a separate assessment so the result includes the cost of choosing.
14 sections · 3 questions · 1 coding challenge
The arrow keys move between sections too.
The Search Can Overfit Too
BOTIE
Nested cross-validation separates the search from an outer assessment. The outside observations ask whether the entire inner choosing procedure produces useful predictions on data it did not use.
The Winning Score Has Been Chosen for Looking Good
Botie tries several feature sets and regularisation strengths. One has the lowest validation error, so we keep it. That is a reasonable development decision. Reporting that same winning score as an independent assessment is another matter.
The validation results helped choose the winner. Some of its advantage may belong to the particular observations we happened to use. We need fresh observations outside that choosing process.
These are invented recorded fold losses. The workshop audits selection and aggregation; it does not run cross-validation training.
Step 1 of 2
One outer fold has a boundary around the search
All inner training and validation happen inside the outer training portion.
- 1
Outer split
- Outer training data
- Untouched outer test
- 2
Inside outer training
- Inner fits and validation
- Choose settings
- 3
Assessment
- Refit chosen settings on outer training
- Predict outer test
Step 2 of 2
The tempting outer winner is ineligible to choose itself
Rows represent outer folds and columns represent candidate procedures A and B.
| Fold | Inner A | Inner B | Outer A | Outer B | Inner choice |
|---|---|---|---|---|---|
| 1 | 1 | 2 | 4 | 2 | A |
| 2 | 3 | 1 | 2 | 5 | B |
1
- Inner A
- 1
- Inner B
- 2
- Outer A
- 4
- Outer B
- 2
- Inner choice
- A
2
- Inner A
- 3
- Inner B
- 1
- Outer A
- 2
- Outer B
- 5
- Inner choice
- B
Evaluate the search procedure
The selection wire never receives outer results. The outer reader only assesses the choice already made.
Keep the outer answers out of the choice
Select each fold’s candidate using its inner validation losses. Only then read that candidate’s outer loss.
BOTIE
Mean selected outer loss
4.5
Follow the operations
1. Outer losses by fold and candidate
4 2 2 5 2. Inner losses by fold and candidate
1 2 3 1 3. Choose using inner validation only
- 00
- 11
4. Read the selected outer losses
- 04
- 15
5. Mean
4.5
6. Result
4.5
Recorded losses audit the protocol. A real nested run must also enforce split boundaries while fitting each complete pipeline.
1. State whether we are evaluating a model or a procedure
A frozen candidate assessed on a held-out test set answers a question about that fitted candidate. Nested cross-validation assesses a procedure that includes selecting settings and fitting. Different outer folds may choose different settings.
Neither description makes the other unnecessary. A development team may use nested evaluation to compare procedures, then train its final chosen pipeline and assess it on a separately reserved dataset.
Write down the object being evaluated before selecting a split design.
2. Create an outer boundary first
Set aside one outer test portion. The rest is the outer training portion, containing every record available to the inner search. The inner search divides that portion again to fit candidate pipelines and score them.
The outer test labels cannot select features, thresholds, stopping epochs or hyperparameters. Treat all those choices as part of the procedure. A manual feature decision informed by outer errors is still selection.
Outer training → inner training + inner validation
Outer test → assessment onlyFor new patients or machines, split at that group boundary. For forecasting, preserve the available history at each origin. Nesting does not fix an inappropriate split.
3. Choose inside, refit, then look outside
Average each candidate’s inner validation losses using a declared aggregation rule. Select the candidate with the lowest loss. Refit its complete pipeline on the outer training portion, then predict the outer test portion once.
Repeat across outer folds. Report the outer assessment results, not the average of the best inner scores. Declare whether folds receive equal weight or predictions are pooled; those differ when fold sizes differ.
Inner choices: [A, B]
Selected outer losses: [4, 5]
Equal-fold mean = (4 + 5) / 2 = 4.5Our teaching tables assume equal-size outer folds. The practice function explicitly reports an equal-fold mean.
Check yourself
Questions on Parts 1 to 3
Question 1 of 2
Which outer result enters the assessment?
Use the information below.
Inner losses: A=1, B=2. Outer losses: A=4, B=2. Select by inner loss only.4. Fit transformations inside the same boundary
Imputers, scalers, feature selectors and learned encoders must be fitted on the current training partition. Even an unsupervised scaler can leak distribution information if it sees the outer test data before evaluation.
In scikit-learn, a Pipeline inside GridSearchCV keeps fitted preprocessing with the estimator. Cross-validating that search object creates the outer assessment. Supplying a transformed full dataset before the search defeats that boundary.
outer training
→ fit inner pipeline on each inner training split
→ score each inner validation split
→ select settings
→ refit entire pipeline on outer training
→ transform and predict outer testFor grouped searches, ensure both levels actually receive and respect group information. API convenience does not establish a correct information boundary.
Run in your own environment
Run the complete nested search with scikit-learn
The workshop audits recorded losses. This reference actually fits a scaled ridge-regression pipeline inside an inner search and evaluates that whole search in outer folds. The synthetic observations are independent by construction; this split is not a template for grouped records or time series.
Run in a Python environment with NumPy and scikit-learn installed. This reference is separate from the NumPy-only browser challenge.
Record package versions when saving results. The code creates a synthetic dataset and does not contact a provider or download records.
import numpy as np
from sklearn.linear_model import Ridge
from sklearn.model_selection import KFold, GridSearchCV, cross_val_score
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
rng = np.random.default_rng(7)
X = rng.normal(size=(60, 2))
y = 10 + 2 * X[:, 0] + 4 * X[:, 1] + rng.normal(size=60)
pipeline = Pipeline([
("scale", StandardScaler()),
("ridge", Ridge()),
])
inner = KFold(n_splits=3, shuffle=True, random_state=11)
outer = KFold(n_splits=5, shuffle=True, random_state=19)
search = GridSearchCV(
pipeline, {"ridge__alpha": [0.1, 1.0, 10.0]},
scoring="neg_mean_squared_error", cv=inner, refit=True,
)
outer_mse = -cross_val_score(
search, X, y, cv=outer, scoring="neg_mean_squared_error"
)
print("Outer MSEs:", outer_mse)
print("Equal-fold mean MSE:", outer_mse.mean())
# After settling the procedure, fit it on all development observations.
# This fitted object's best_score_ is an inner selection score.
search.fit(X, y)
print("Final development settings:", search.best_params_)GridSearchCV refits the selected complete pipeline on each outer training portion. Its scaler therefore never fits on that fold’s outer test inputs.
Scikit-learn scorers maximise scores. neg_mean_squared_error is negated again here to report ordinary nonnegative MSE. The final search.fit uses all development data; its best_score_ must not replace the outer assessment.
These runs do not supply a fresh final test set. Changing the procedure after inspecting outer scores requires new assessment evidence.
Scikit-learn: nested versus non-nested cross-validation. Documentation checked .
5. Do not promote the best outer fold to the final model
The outer folds are assessment runs, not contestants. Picking the fold with the best score creates another selection. After settling the procedure, run its search on the full development dataset and refit the selected pipeline there.
If you change the search space after inspecting outer results, those results have informed development. Reserve new evidence for the resulting procedure. Report the number and nature of those decisions.
Fold scores share overlapping training data. Their standard deviation is descriptive and is not automatically a valid standard error from independent experiments.
6. Audit selection with explicit array axes
In the tables below, axis 0 is outer fold and axis 1 is candidate. argmin along axis 1 gives one choice per fold. Advanced indexing then picks one outer score from each corresponding row.
The challenge combines the two operations and checks that malformed tables cannot silently broadcast.
Read a candidate from each fold
These choices are supplied so we can inspect the row-and-column indexing separately.
import numpy as np
outer = np.array([[8., 3.], [4., 7.]])
choices = np.array([1, 0])
print(outer[np.arange(2), choices].tolist())[3.0, 4.0]Each row contributes exactly one selected score. Flattening the table would lose the fold boundary.
7. Pay for the question you need answered
Nested evaluation repeats fitting many times, so it can be expensive. A sufficiently large independent test set with a disciplined development process may answer the immediate question more simply. If data are limited and model selection is substantial, nesting helps expose that selection to independent outer cases.
Record the candidate space, splits, seeds and software versions. A repeated experiment should reproduce the protocol, not merely a rounded final average.
Use nesting where it answers the evaluation question. More folds cannot manufacture missing populations or future conditions.
Check yourself
Questions on Parts 1 to 7
Question 1 of 1
What should the final fitting step normally do?
Use the information below.
Different outer folds select different hyperparameters.Try it with Botie
Build with Botie
Write and run Python