Train Test Split
A train-test split divides a dataset into a training set and a test set.
Why Judging a Model on Its Own Data Misleads
Suppose you have a dataset and want to build a machine learning model from it. A natural question follows: how will you know whether the model is any good? If you judge the model only on the same data it was built from, you are measuring how well it fits examples it has already seen. That is not the same as measuring how well it will handle new cases. The train-test split is the standard way to keep those two questions apart.
This article follows one small Python program that classifies records from the iris dataset with the k-Nearest Neighbors algorithm. The program is short, but it contains every step a typical supervised learning workflow needs: split the data, fit a model, and evaluate it. As you read, keep one question in mind at each line: what new piece of information exists now that did not exist before? Tracking that question is how you find where a result went wrong.
What do you think happens?
The program prints a score of 0.97. What does that number actually count?
Reveal answer
The fraction of held-out test instances the model labels correctly.
The score() method evaluates the fitted model on the held-out testing data. A score of 0.97 means about 97 percent of those test instances were labeled correctly, under this particular split and this value of n_neighbors.
Splitting the Data Before Any Model Exists
A train-test split divides a dataset into a training set and a test set. In the source's scikit-learn style, the train_test_split() function receives the data array X (input features) and the target array y (labels), and returns four objects: X_train, X_test, y_train, and y_test. The X values hold the features and the y values hold the labels, so each split keeps every feature row matched with its label.
The split happens before the model is trained. The order of events matters: the training set is the only part the classifier sees when it is fitted, and the test set is held back until evaluation. The split is therefore a deliberate decision about which data the model is allowed to learn from and which data is reserved for judging it.
The source passes random_state=0 to the split. The random_state parameter makes the random splitting reproducible: running the same code again produces the same split and therefore the same score. Without a fixed value, a different random arrangement of the data can lead to a different score, so the number you report depends on the split you happened to draw.
How k-Nearest Neighbors Votes on a Label
The k-Nearest Neighbors classifier is a classification algorithm. To predict the label of a new instance, it looks at the k training instances closest to that new instance and takes a majority vote among their labels. The label that appears most often among those neighbors becomes the prediction. The letter k is the number of neighbors considered.
The number of neighbors is passed as n_neighbors when the classifier is created, as in KNeighborsClassifier(n_neighbors=n). It is a hyperparameter: a setting you choose before training rather than a value the model learns from the data. The source example uses n_neighbors=1, which means each prediction simply copies the label of the single closest training point. With a larger k, the vote involves several neighbors, so the same training data can produce different predictions for different values of k. This matters at evaluation time, because the score you get depends on the settings you chose.
Tracing the Pipeline Line by Line
The program below reconstructs the steps the source describes. Read it as a sequence of state changes. Before each line, ask what information exists now that did not exist before.
0.97load_iris()supplies the data and target arrays that become X and ytrain_test_split()returns four objects; the test portion is held backn_neighbors=1 is chosen before training, as a hyperparameterfit()sees only X_train andy_trainscore()is called on X_test andy_test, which the model never saw during fitting
Following the state through the pipeline
Which objects exist after each step, and which of them the classifier is allowed to learn from?
- 1Load the full dataset
X holds the input features and y holds the labels for every record. Nothing has been split yet.
- 2Split
train_test_splitreturns X_train, X_test,y_train, andy_test. Each feature row remains paired with its label in both halves. - 3Create the classifier
KNeighborsClassifier(n_neighbors=1)exists, but it has not learned anything yet. The value 1 was chosen by the programmer. - 4Fit
knn.fit(X_train, y_train)uses only the training portion. The test portion has not been touched. - 5Score
knn.score(X_test, y_test)predicts labels for the held-out features and compares them with the held-out labels. The fraction that match is the score.
The printed value is 0.97. It reflects a model built only from the training portion and judged only on the test portion.
The flow from the full dataset through the split, the fit step, and the score step is shown in the pipeline diagram below.
Reading the score() Output
The score() method evaluates the model's performance on the held-out testing data. The result is an accuracy-style score, and the source formats it with print to two decimal places. A score of 0.97 means the classifier labeled about 97 percent of the held-out test instances correctly, under the conditions of this particular split and this value of n_neighbors.
Roles of the Training and Test Sets
The two parts have different jobs. The training set is the material the model is built from. The test set is held back and used afterward to check the model's performance on data it was not built from. The test set is described as containing data that is new to the model, which is exactly what makes it useful for judging generalization.
Notice that the test set reaches the evaluation step but does not feed into building the model. That separation is the whole point of the technique. If the test set were also used to build the model, it would no longer be data the model had not seen, and the evaluation would lose its meaning.
Mistakes That Break the Split
Common mistake Fitting the model on the full dataset before splitting
What it looks likeknn.fit(X, y) followed by knn.score(X_test, y_test)Why it failsThe model has already seen the rows that are supposed to be held back, so the score measures memorization of those rows rather than generalization.
Do this insteadCall fit() with X_train and y_train only.Common mistake Judging a model only on the data it was built from
What it looks likeReporting knn.score(X_train, y_train) as the model's qualityWhy it failsThis measures how well the model fits examples it already saw, which is not the same as how it will handle new cases.
Do this insteadEvaluate on X_test and y_test, the held-out portion.
Common mistake Choosing settings by repeatedly checking the test score
Why it failsIf you keep adjusting
n_neighborsuntil the test score looks best, the test set has effectively become part of model building, and the reported score is optimistic.Do this insteadKeep the test set for a final evaluation and make decisions with separate data.
Common mistake Forgetting the split settings when reporting a score
Why it failsThe score depends on the random arrangement and on
n_neighbors, so a number without its settings cannot be reproduced or compared.
Practice: Diagnosing an Unexpected Score
A colleague runs the program above but changes the classifier line to KNeighborsClassifier(n_neighbors=5) and leaves everything else the same. Before running it, describe which line changed the state of the model, and which stage of the pipeline you would inspect first if the new score looked far too high.
Hints
n_neighborsis a hyperparameter chosen before training.- Ask which objects differ between the two runs: the classifier setting, the split, or the test data.
- Check whether
fit()was still called with X_train andy_trainonly.
Explain, in your own words, why a score computed on the training data would be a misleading measure of how the model will handle new records.
Hints
- Think about which rows the model was fitted on.
- The test set is described as containing data new to the model.
Key Takeaways
- A train-test split divides a dataset into a training set, used to build the model, and a test set, held back to evaluate it on data the model has not seen.
- A k-Nearest Neighbors classifier predicts a label by majority vote among the k training instances closest to a new instance;
n_neighborsis a hyperparameter chosen before training. - The pipeline is split, fit on the training portion only, then score on the held-out test portion. The score is the share of test instances labeled correctly under that specific split and setting.
- Mistakes such as fitting on the full dataset, scoring on training data, or tuning against the test set break the purpose of the split.
- Fixing
random_statemakes the split reproducible, and any reported score should be recorded with its split and parameter settings.