Introduction to Model Evaluation with scikit-learn
The first is the model to evaluate, the second is the data (the features), and the third is the target (the ground-truth labels).
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…
Running a Complete Evaluation
This article starts by running a complete evaluation before explaining any of its parts. The program loads the iris dataset, creates a logistic regression model, and asks scikit-learn to evaluate that model with cross-validation. Read the program once, then look at the line it prints. The rest of the article explains how that line is produced and what each number in it means.
An array of accuracy values, one per fold. This article does not show exact numbers; the length of the array is the part to focus on.load_iris(return_X_y=True)returns the features as X and the labels as yLogisticRegression()creates the model that will be evaluatedcross_val_scoreis called with no cv argument, so the default number of folds is usedprint(scores)shows the returned array
What do you think happens?
When cross_val_score is called without a cv argument, how many values will the printed array contain?
Reveal answer
Three, one per fold
The default is three-fold cross-validation, and the function returns one accuracy value for each fold. The length of the array therefore matches the number of folds, which is three by default.
The Three Inputs to the Call
Before moving on, notice the three objects in the call: the model, the data, and the labels. The general form of the call takes these as its first three positional arguments. The first is the model to evaluate, the second is the data (the features), and the third is the target (the ground-truth labels). Those three inputs are all that cross_val_score needs to run the evaluation. The next question is what it hands back.
- model: the scikit-learn estimator to evaluate
- X: the features, one row per sample
- y: the target labels, one per row of X
- cv: optional, sets how many folds are used
cross_val_score evaluates a model with cross-validation. Its main parameters are the model, the data, and the target. The cv argument is optional and controls the number of folds.
Splitting Data into Folds
Cross-validation evaluates a model by splitting the data into folds and then training and testing on different subsets. In K-fold cross-validation, the data is split into k subsets. The model is evaluated once for each fold, so the function produces one score per fold. The default for cross_val_score is three-fold cross-validation, which means the data is divided into three subsets.
Each fold holds out one subset as test data and trains on the remaining subsets. The held-out subset changes from fold to fold, so every subset is held out exactly once. The diagram below shows the three-fold case. Read it as a rotation: the same three blocks appear in every fold, but a different block is the test block each time.
In the fold where a block is held out, the model is scored on that block. In every other fold, the same block is part of the training data. Because each block is the test block exactly once, the three scores together cover the whole dataset rather than resting on one arbitrary split.
What Happens Inside One Fold Cycle
Within a single fold, the work follows a fixed sequence: the model is fit on the training rows, it predicts on the held-out rows, and the predictions are scored as accuracy. Then the process moves to the next fold and repeats. The diagram traces one pass through this cycle.
The loop runs once per fold. With three folds, the sequence runs three times, and each run produces one accuracy value. The model is retrained from the training rows in each fold, so the three results are independent evaluations of the same model on different held-out blocks.
Reading the Returned Array
The value cross_val_score returns is an array, and each element is the result of one held-out fold. A single number is not the result of the whole procedure. The array is a list of per-fold results, and its positions follow fold order: the first element comes from the first fold, the second from the second fold, and so on.
Changing the Number of Folds with cv
The cv parameter sets the number of folds, and the length of the returned array matches that number. The next example keeps the same model and data and passes cv=5. Predict the length of the array from the rule above before you run it: the array should contain five values, one for each of the five folds.
An array of five accuracy values, followed by the number 5.- The model and data are unchanged from the first program
- Only the cv argument differs
len(scores)counts the values in the returned array
| Call | Folds used | Length of returned array |
|---|---|---|
| cross_val_score(model, X, y) | three (default) | 3 |
| cross_val_score(model, X, y, cv=5) | five | 5 |
Changing cv changes the number of folds and the number of returned values together
Tracing Where an Output Diverges
When an output does not match your expectation, the useful question is where the divergence began. Work through the chain in order: the inputs you passed, the value of cv, the number of values in the array, and then the values themselves. Checking in this order lets you find the failing step instead of rereading the whole program.
- 1Check the inputs: confirm that the model, the features, and the labels are the ones you intended
- 2Check cv: confirm whether you passed a value, and what it is
- 3Check the length: count the values in the array and compare it with the number of folds
- 4Check the values: only if the length is right, examine the individual accuracy numbers
A mismatch in length usually points to the cv argument. A mismatch in the values, with the correct length, points to the data or the model, because the same fold structure was used. This split tells you which part of the call to inspect first.
Mistakes That Hide the Fold Count
Common mistake Expecting a single overall score from the call
What it looks likescores = cross_val_score(model, X, y) followed by reading scores as one accuracy numberWhy it failsThe function returns one accuracy value for each fold, so the result is an array of per-fold results.
Do this insteadTreat scores as a list with one entry per fold, and compute any summary from it deliberately.
Common mistake Assuming the output length is always three
What it looks likePassing cv=5 and expecting three printed values
Why it failsThree is only the default. The cv parameter sets the number of folds, and the array length matches it.
Do this insteadPredict the length from the cv value, then check it with len(scores).
Common mistake Rereading the whole program when output looks wrong
What it looks likeScanning every line of the code after seeing an unexpected printed array
Why it failsThe divergence usually starts at a specific step, and the array length narrows it quickly.
Do this insteadFollow the ordered chain: inputs, cv, length, then values.
Practice: Predicting the Output
Without running the code, predict how many values the following call returns, and explain your reasoning in terms of folds: scores = cross_val_score(model, X, y, cv=10). Then say which fold produced the first value in the array.
Hints
- The cv parameter sets the number of folds.
- The length of the returned array matches the number of folds.
- The array positions follow fold order, so the first position comes from the first fold.
Locating a length mismatch
A learner expects five values from cross_val_score(model, X, y, cv=5), but the printed array has three values. Where should the investigation start?
- 1Check the inputs
The model, features, and labels are the same as intended, so the inputs are not the first suspect.
- 2Check cv
The call has cv=5 in it, so the requested fold count is five. The mismatch is not explained by a missing argument.
- 3Check the length
Three values against an expected five is a length mismatch, which the source identifies as pointing to the cv argument.
- 4Locate the call
Look at the exact call that produced the array. A different cv value in the code that actually ran, such as a leftover default or an edited copy, would explain three values.
The divergence began at the cv argument, because the length of the array is the first thing to check. The values themselves do not need to be examined until the length matches.
Key Takeaways
cross_val_scoretakes a model, data, and target, and it returns an array with one accuracy value per fold.- By default it uses three-fold cross-validation, so the default output has three values; the cv parameter changes the fold count and the array length together.
- Each fold holds out one subset as test data and trains on the rest, and the array positions follow fold order.
- When output looks wrong, check the inputs, then cv, then the array length, and only then the individual values.