Looking at Your Data Before Modeling
A model that can remember its training data will look perfect on that data, so the training data cannot be used to judge whether the model generalizes.
Why a Model Cannot Grade Its Own Homework
The goal of this chapter is a model that can predict the species of an iris from a new set of flower measurements. Building such a model is only half the job. Before anyone applies it to real measurements, we need to know whether it actually works and whether its predictions deserve trust. This article covers the first step in answering that question: deciding which data we use to build the model and which data we use to check it.
What do you think happens?
Suppose you train a model on the 150 flower measurements and then ask it about those same 150 flowers. It gets almost everything right. What does that tell you?
Reveal answer
The second option. A near-perfect score on the training data does not show that the model will work on new flowers.
A model with enough flexibility can store the whole training set. It then reproduces every correct answer, which looks like success even though it has not captured a pattern that carries over to unseen measurements.
The intuition behind the first option feels reasonable. The model has seen these examples, answers them correctly, and so seems to have learned something useful. The trap is that the same behavior can come from two very different models. One has learned a general pattern. The other has memorized its inputs. On the training data alone, the two look identical. The rest of this article shows how the data is divided so that the difference can be seen.
Overfitting: When Memorizing Looks Like Learning
The phenomenon behind this misconception has a name: overfitting. A model overfits when it remembers the training data instead of generalizing well from it. When it does, it reproduces the correct answer for every training point. That looks like success, but the model has not captured a pattern that carries over to measurements it has never seen.
Overfitting is the situation in which a model remembers its training data instead of generalizing from it. The remembering behavior is invisible when the model is scored on the training data itself.
Splitting the Labeled Table in Two
The solution is to hold some labeled data back. We show the model examples it has not seen during building, for which we still know the correct labels. In practice, the labeled data we have collected, here 150 flower measurements, is split into two parts. One part builds the model and is called the training set or training data. The rest assesses how well the model works and is called the test set, test data, or hold-out set.
Rather than cutting the table by hand, scikit-learn provides train_test_split, which shuffles the dataset and splits it for you. It extracts 75% of the rows as the training set, together with the corresponding labels. The remaining 25% of the rows, with the remaining labels, becomes the test set. You do not decide which individual flowers go where; the function handles that.
The exact amount for each part is somewhat arbitrary. A test set holding 25% of the data is nonetheless a good rule of thumb, and it is the proportion the function uses by default. For the 150 flowers, 75% is 112.5 rows and 25% is 37.5 rows, so the counts that actually appear depend on how the function rounds. The next section works through the real shapes.
Why Shuffling Comes Before Splitting
A simpler approach would be to take the first 75% of the rows for training and the last 25% for testing. The function does not do this. Before making the split, train_test_split shuffles the dataset using a pseudorandom number generator. The reason becomes clear once you consider how the iris data is ordered.
The data points are sorted by their label. If the last 25% were used as the test set, every point in it would carry the label 2. A test set containing only one of the three classes would tell us very little about how well the model generalizes across the species. Shuffling makes sure the test data contains examples from all classes.
What an unshuffled cut would do
The 150 rows are sorted so that the first 50 carry one label, the next 50 another, and the last 50 a third. Taking the last 25% as the test set means taking the last 37 or 38 rows.
- 1Locate the tail of the sorted table
The last rows of a label-sorted table all belong to the final class.
- 2Check the classes in the test set
The test set would contain only one of the three classes, so it cannot show how the model handles the other two.
- 3Compare with a shuffled split
After shuffling, rows from every class are spread across both parts, so the test set reflects all species.
Shuffling is what makes the test set a fair sample of all three classes.
Reading X and y Without Confusing Them
In scikit-learn, data is usually denoted with a capital X and labels with a lowercase y. The convention is inspired by the standard mathematical formulation $f(x)=y$, where x is the input to a function and y is its output. The capitalization carries meaning. X is a two-dimensional array, a matrix with one row per flower. y is a one-dimensional array, a vector with one label per row.
Because train_test_split returns X and y together in one call, row i of X_train and row i of y_train describe the same flower. The pairing is held by the position in the arrays. If the two were split separately and then shuffled independently, the measurements would no longer line up with their labels, and the model would learn from wrong pairs. Splitting both in one call is what keeps them aligned.
Making the Split Repeatable with random_state
Shuffling is random, which raises a practical problem: running the same code twice could produce two different splits. To get the same output every time, you provide the pseudorandom number generator with a fixed seed through the random_state parameter. With the seed fixed, the outcome is deterministic and the line always produces the same split. The source book fixes random_state whenever it uses a randomized procedure, and the same habit is worth adopting whenever you want results you can compare.
X_train, X_test, y_train, y_test = train_test_split(X, y)Each run shuffles differently, so the test rows can change between runs.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)The seed is fixed, so every run produces the same split.
Reading the Shapes of the Four Arrays
The four outputs are NumPy arrays. X_train holds 75% of the rows of the dataset and X_test holds the remaining 25%. The shape attribute reports how many rows and columns each array has, so it is a quick way to confirm that the split did what you expected. Each iris row has four measurements, so the feature arrays should be four columns wide and the label arrays should be one-dimensional.
(112, 4) (38, 4) (112,) (38,)- The import brings in the splitting function.
random_state=0 fixes the shuffle so the split is repeatable.- The four names are assigned in the order the function returns them.
- shape reports rows and columns for each array.
| Array | Holds | Expected shape | What a wrong shape signals |
|---|---|---|---|
| X_train | Measurements for the training part | (112, 4) | Column count other than 4 means the features were lost or reshaped |
| X_test | Measurements for the test part | (38, 4) | Column count other than 4 means the features were lost or reshaped |
| y_train | Labels for the training part | (112,) | A two-dimensional shape means labels were not kept as a vector |
| y_test | Labels for the test part | (38,) | A row count that differs from X_test means the pairing has broken |
Expected shapes for a 75/25 split of 150 iris rows, with the signal each mismatch gives
Suppose X_test has shape (38, 4) but y_test has shape (37,). The row counts disagree, so the labels no longer match the measurements. Checking shapes right after the split reveals this immediately, before any model is trained on the broken arrays.
Mistakes When Splitting Labeled Data
Common mistake Judging the model on the data it was trained on
What it looks likeReporting a near-perfect score from predictions made on the same 150 flowers used to build the model.
Why it failsA model that memorized its training data scores perfectly there, which says nothing about new measurements.
Do this insteadScore the model only on the held-out test set.
Common mistake Taking the last 25% of an ordered table as the test set
What it looks likeSlicing the final rows of label-sorted data for testing.
Why it failsThe test set may contain only one class, so it cannot show how the model handles the others.
Do this insteadLet train_test_split shuffle the rows before splitting.
Common mistake Leaving random_state out when results must be compared
What it looks likeRunning the split twice and getting different test rows, then wondering why scores changed.
Why it failsWithout a fixed seed, every run shuffles differently, so the comparison is between different test sets.
Do this insteadPass a fixed random_state such as 0 when results must be repeatable.
Common mistake Splitting X and y separately
What it looks likeCalling train_test_split on X alone and then again on y.
Why it failsThe two shuffles can differ, so the measurements no longer line up with their labels.
Do this insteadPass X and y to a single call so the four outputs stay paired.
Common mistake Skipping the shape check after the split, so a broken array goes unnoticed until the model fails
Practice: Predict the Shapes Before Running
A labeled dataset has 150 rows and 4 feature columns. You call train_test_split(X, y, random_state=0) with the default proportions. Before running anything, write down the shapes of X_train, X_test, y_train, and y_test. Then run the code and compare. If the shapes differ from your prediction, identify which array's shape is the first to disagree.
Hints
- The default split gives the test set 25% of the rows, and 37.5 rounds to a whole number of rows.
- The feature arrays keep the 4 columns; the label arrays are one-dimensional.
- Check the row counts of X_test against
y_testfirst, since they must match.
Explain, in two sentences, why a model that scores perfectly on its training data might still fail on new flowers.
Hints
- Think about what memorizing the training set would produce.
- Name the set that is needed to expose the difference.
Key Takeaways
- A model that memorizes its training data scores perfectly on that data, so the training data cannot judge whether it generalizes; overfitting is the name for this memorizing behavior.
train_test_splitshuffles the labeled rows and, by default, puts 75% into the training set and 25% into the test set, returning X_train, X_test,y_train, andy_testin one call.- The
random_stateparameter fixes the shuffle so that the same split is produced every time; without it, each run may produce different test rows. - Checking the shapes of the four arrays, with four feature columns and one-dimensional labels, is the quickest way to find where a split diverged.