Train and Test Splits
ShuffleSplit repeats a random split: each iteration draws train_size points for training and test_size disjoint points for testing.
Starting From a Fitted Model
Linear regression is a good first model to study because almost everything it does is visible in a few lines of code. Instead of starting with a definition, this article starts with what happens when you fit the model. You will follow the execution line by line and keep track of what exists in Python after each step. The goal is to understand where the numbers that a model uses come from, and then to see how the train and test splits that feed the model are produced.
What Fitting Writes Into the Model
Linear regression, also called ordinary least squares or OLS, is the simplest and most classic linear method for regression. Its goal is to choose two numbers, a slope $w$ and an offset $b$, so that the line they define makes predictions that sit as close as possible to the true target values $y$ on the training set. When the data has a single input feature, the prediction is the slope multiplied by the input, plus the offset. Once the two numbers are chosen, the model needs no other information about the training data to make a prediction.
Fitting means choosing $w$ and $b$ so that the error is as small as possible. The error used here is the mean squared error. For each sample, take the difference between the prediction and the true value, square that difference, and add up the squares. Squaring removes the sign of each miss, so a prediction that is too high and one that is too low both count as errors, and large misses count for much more than small ones. The word mean refers to dividing that sum by the number of samples $n$, so the error does not grow just because the dataset grows.
The small program below computes this quantity by hand for two samples. Read it as a template for the calculation that fitting tries to drive down, not as the code used to train a model.
0.625- The first miss is 2.5 minus 3.0, which is -0.5; squared it is 0.25
- The second miss is 6.0 minus 5.0, which is 1.0; squared it is 1.0
- Dividing the sum 1.25 by the two samples gives 0.625
In scikit-learn, the model is created from the LinearRegression class and fitted with the training features and targets. The fit method returns the fitted model, which is why the two steps can be written on one line. After fitting, the slope is in the coef_ attribute and the offset is in the intercept_ attribute.
LinearRegression()creates the model object, which only describes what it will do- .fit(X_train,
y_train) reads the training data and writes the learned values into the model - coef_ holds one slope per input feature, so it is an array
- intercept_ holds the offset as a single float
model = LinearRegression()The model object exists and describes the linear regression procedure, but it holds no values learned from training data
model = LinearRegression().fit(X_train, y_train)coef_ and intercept_ hold the slope and offset derived from the training data, and the model can make predictions
Reading Training and Test Scores Together
A fitted model's score method reports $R^{2}$ on whatever data you pass it. $R^{2}$ is a measure of how well the model explains the data. Calling score on the training data tells you how well the model fits the examples it learned from. Calling score on the test data tells you how well the model generalizes to examples it has not seen. Because the score describes whichever set you pass in, the two results must be compared together rather than read alone.
The two numbers are read together. When both scores are low and close to each other, the model is probably underfitting, meaning it is too simple to capture the pattern in the data. When the training score is high and the test score is much lower, that gap is a clear sign of overfitting.
Model complexity is part of the picture. A model with a single feature is simple, so there is little danger of overfitting it. A dataset with many features gives a linear model much more room to bend toward the particular training examples, and the chance of overfitting rises. The source illustrates this with the extended Boston Housing dataset, which has 506 samples and 105 derived features.
Diagnosing a gap between training and test scores
After splitting the data and fitting the model in the usual way, the training score is 0.95 and the test score is 0.61. What does this result indicate?
- 1Compare the two scores
The training score is 0.95 and the test score is 0.61. The gap between them is 0.34.
- 2Ask which pattern this matches
The scores are not both low and close together, so this is not the underfitting pattern. The training score is high and the test score is much lower.
- 3Interpret the gap
The model predicts the training examples very accurately but generalizes much worse to the held-out examples. A discrepancy like this is a clear sign of overfitting.
The result diverges from expectation: the model does well on data it has seen and poorly on data it has not, which points to overfitting.
How One Shuffle-Split Iteration Picks Points
ShuffleSplit repeats a random split. A single iteration works in two draws from the same dataset. First, it selects train_size points to form the training set. Then it selects test_size points to form the test set, and those test points are chosen so that none of them is also in the training set for that iteration. The model is trained on the first group and scored on the second. Because the two groups are disjoint within an iteration, no point can be used both to learn and to be judged in the same iteration.
The sizes can be given as whole numbers or as fractions. A whole number is an absolute count of points, while a floating-point value is a fraction of the whole dataset. With the values 0.5 and 0.5, each training set holds half of the rows and each test set holds the other half of the same size.
In the illustration, the five training points and the five test points together account for every point in the dataset, and no point appears in both groups. The next iteration draws again, so a point that was test data in this iteration can appear in a later training set.
n_splits=10 asks for ten iterationstrain_size=0.5 andtest_size=0.5 give each iteration half the rows for training and the other half for testing- Each pass through the loop produces one training group and one test group
How n_splits Multiplies the Draws
Two settings in ShuffleSplit do different jobs. The n_splits argument (called n_iter in the textual description) decides how many times the splitting happens. The train_size and test_size arguments decide how big each split is. Because these are separate, you can ask for many iterations while keeping each split small, or for few iterations with large splits.
The source describes a run of four such iterations on the same ten-point dataset, each drawing its own training and test points. Because each iteration samples again, a point that serves as test data in one iteration can appear in the training set of a later one. This is what gives the method its variety, and it is also why the ten scores in the first example differ from each other. Each iteration produces one score, so the total count of scores equals n_splits.
- The iris dataset is scored with a logistic regression model
- Instead of one fixed split, ShuffleSplit supplies ten different splits
- One score is returned per split, so the length of scores equals
n_splits
Where Shuffle-Split Surprises Happen
Most surprises with shuffle-split come from a few predictable places. When a result differs from what you expected, look at the setup lines first, then at what each line returned.
Common mistake Expecting one identical score on every run
What it looks likeTen scores come back and they are not all the same value.
Why it failsEach iteration resamples, so the individual scores differ from run to run. The variety is intended.
Do this insteadRead the spread of the scores as information about how sensitive the result is to which points were drawn.
Common mistake Assuming the whole dataset is always used
What it looks likeSetting train_size to 0.2 and test_size to 0.2 and assuming every row is involved.
Why it failstrain_sizeandtest_sizecan sum to less than one, so each iteration uses only part of the data.Do this insteadAdd the two sizes. If the sum is below one, the leftover rows are left out of every split. This is useful when experimenting with large datasets, because a smaller subsample can be enough to explore an idea quickly.
Common mistake Treating n_splits and split size as the same setting
What it looks likeRaising n_splits and expecting each split to grow as well.
Why it failsn_splitscontrols how many iterations run, and it is set separately from the size of each split.Do this insteadChange n_splits for the number of iterations and train_size or test_size for the size of each split.
Common mistake Reading only the training score
What it looks likeA training score of 0.95 is reported as proof that the model works.
Why it failsThe score describes whichever set it was computed on. A high training score says little about examples the model has not seen.
Do this insteadCompare the training score with the test score together before deciding whether the model is underfitting or overfitting.
Choosing StratifiedShuffleSplit for Classification
StratifiedShuffleSplit is a stratified variant of ShuffleSplit. Its main use is classification problems, where the source says it can give more reliable results than plain shuffle-split. The name hints at the difference: the word stratified refers to keeping each split organized by the class labels, so that the training and test sets reflect the classes in the data rather than depending only on chance.
| Feature | ShuffleSplit | StratifiedShuffleSplit |
|---|---|---|
| How points are chosen | Random draw of train_size and test_size points | Random draw organized by the class labels |
| Class balance in each split | Depends on chance | Reflects the classes in the full dataset |
| Main use | General random repeated splitting | Classification problems |
| Controls | n_splits, train_size, test_size | n_splits, train_size, test_size, organized by class labels |
Random splitting versus class-aware splitting
When you are splitting data for a classification task, prefer StratifiedShuffleSplit when you want each split to keep the class structure of the full dataset. Plain ShuffleSplit can produce splits whose class mix differs from the whole, because the draw depends only on chance.
Practice: Trace a Split
A dataset has 10 rows. You create ShuffleSplit with n_splits=4, train_size=0.5, and test_size=0.5, then loop over the splits. How many iterations run, how many rows are in each training set, and how many rows are in each test set? Then say whether a row can be in both the training set and the test set of the same iteration.
Hints
n_splitssets the number of iterations, separately from the size of each split- A fraction of 0.5 of 10 rows is 5 rows
- Within one iteration, the test points are chosen so that none of them is also in the training set
What do you think happens?
With train_size=0.5 and test_size=0.5 on a 10-row dataset, how many training rows does each iteration use?
Reveal answer
5 training rows
A fraction of 0.5 means half the dataset, and half of 10 rows is 5. The test set is also 5 rows, and the two groups do not overlap within the iteration.
What do you think happens?
If train_size=0.2 and test_size=0.2 on a 10-row dataset, what fraction of the data is used in each iteration?
Reveal answer
40 percent, which is 4 training rows and 2 test rows out of 10
A fraction of 0.2 of 10 rows is 2 rows, so the training set has 2 rows and the test set has 2 rows, using 4 rows in total. The sizes sum to 0.4, which is less than one, so 60 percent of the rows are left out of every split.
Summary of the Splitting Mechanics
- 1Linear regression chooses a slope w and an offset b to minimize the mean squared error on the training set; after fitting, coef_ holds the slope and intercept_ holds the offset.
- 2A score describes the data it is computed on, so training and test scores must be read together to diagnose underfitting or overfitting.
- 3One ShuffleSplit iteration draws
train_sizepoints for training and disjointtest_sizepoints for testing, andn_splitssets how many iterations run. - 4Sizes can sum to less than one, in which case some data is left out of every split; StratifiedShuffleSplit is preferred for classification when the class balance should be reflected in each split.
At a glance
- Linear regression chooses a slope w and an offset b to minimize the mean squared error on the training set; coef_ holds the slope and intercept_ holds the offset after fitting.
- Training and test scores must be compared together: similar low scores suggest underfitting, while a high training score with a much lower test score suggests overfitting.
- Each ShuffleSplit iteration draws
train_sizepoints for training and disjointtest_sizepoints for testing, andn_splitscontrols how many iterations run. - If
train_sizeandtest_sizesum to less than one, only part of the data is used; check this before interpreting results. - StratifiedShuffleSplit is preferred for classification tasks when the splits should reflect the class structure of the data.