Fun with Learning Technology
LearnCoursesQuestionsTracksToolsNewsExplorePractice
Fun with Learning Technology

A new problem, explained clearly, every day.

Subscribe
Learn
  • Lessons
  • Topics
  • News
  • Tools
  • Courses
  • Career tracks
  • Everything
Site
  • About
  • Contact
  • Support
  • Privacy
  • Terms
Get the daily one

One email per new problem. No spam.

Request a tutorial

Requests shape what gets made next.

© 2026 Fun with Learning TechnologyRSS
Home›Courses›Machine Learning›Train / Validation / Test Split

Fundamentals

Train / Validation / Test Split

Data splitting is the practice of partitioning a dataset into distinct subsets to measure model generalization. By separating data, we prevent the model from memorizing specific examples, ensuring it learns underlying patterns instead. This approach is essential whenever we need to evaluate how a model performs on unseen, real-world data.

The Core Philosophy: Separating Seen from Unseen

To understand why we split data, consider that a machine learning model is essentially a function that maps inputs to outputs. If we train a model on a dataset and then test it on the exact same data, we are not measuring its predictive power; we are measuring its ability to memorize. This is known as overfitting. By holding out a portion of the data during training, we create an environment where the model is forced to generalize. The 'Train' set is where the model adjusts its parameters to minimize error. The 'Test' set remains completely hidden from the training process, acting as a final examination. If the model performs well on training data but poorly on the test data, we have identified that the model is merely reflecting the noise of the training set rather than the signal. This separation is the only way to establish a baseline for how a model will perform in production environments.

import numpy as np

# Simulate a dataset of 1000 features
X = np.random.rand(1000, 10)
y = np.random.randint(0, 2, 1000)

# Calculate index for an 80/20 split
split_idx = int(0.8 * len(X))

# Create train and test sets
X_train, X_test = X[:split_idx], X[split_idx:]
y_train, y_test = y[:split_idx], y[split_idx:]
# Now, the model only touches X_train during fitting.

Introducing the Validation Set

While the train and test split solves the memorization problem, it introduces a secondary issue: hyperparameter tuning. If we use the test set to evaluate which learning rate, tree depth, or regularization strength works best, the test set essentially becomes part of the training process. This is 'data leakage.' To fix this, we introduce a third partition: the validation set. We train the model on the training set, use the validation set to iteratively tune hyperparameters and compare different model architectures, and finally use the test set once at the very end. The validation set acts as a sandbox for model improvement, while the test set remains the ultimate, unbiased authority on model quality. This structure prevents 'overfitting to the test set,' a common pitfall where engineers inadvertently bias their model selection towards the specific anomalies found in their final evaluation data.

from sklearn.model_selection import train_test_split

# First split: isolate the test set (e.g., 20%)
X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2)

# Second split: isolate the validation set from the remaining 80% (e.g., 25% of the remainder)
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.25)
# X_train is for fitting, X_val is for tuning, X_test is for final evaluation.

Managing Bias through Randomization

Simply splitting the data linearly, as if it were a flat list, can be dangerous if the underlying data has a temporal or category-based structure. For instance, if your dataset is sorted by date, a linear split would result in a training set from the past and a testing set from the future, which might not reflect the dynamic nature of your target distribution. To mitigate this, we always perform random shuffling before splitting. This ensures that both the training and the evaluation sets contain a representative statistical distribution of the original dataset. Without randomization, you risk having entire classes or specific time periods missing from your test set, leading to biased performance metrics that do not reflect the actual reliability of your model. By randomizing, we maintain the assumption that the training set and the test set are drawn from the same underlying probability distribution, keeping the evaluation meaningful.

import numpy as np

# Ensure randomness to prevent structural bias
indices = np.arange(len(X))
np.random.shuffle(indices)

# Apply the shuffled indices to the dataset
shuffled_X = X[indices]
shuffled_y = y[indices]

# Now proceed with splitting based on these randomized indices
X_train = shuffled_X[:800]
y_train = shuffled_y[:800]

Dealing with Class Imbalance

In real-world scenarios, classes are rarely perfectly balanced. If you are predicting rare events, such as fraud or equipment failure, a random split might result in a training set with only a handful of positive cases, or worse, a test set with no positive cases at all. This makes it impossible to measure metrics like recall or F1-score accurately. The solution is 'stratified splitting.' Stratification ensures that the ratio of classes found in the original dataset is preserved in both the training, validation, and test subsets. By enforcing this constraint, you guarantee that your model is exposed to a representative proportion of the minority class, and your evaluation metrics will be statistically significant across all partitions. Ignoring stratification in imbalanced datasets is a leading cause of models that appear to perform well in training but fail completely when confronted with the minority class in the wild.

from sklearn.model_selection import train_test_split

# y contains class labels (0 or 1)
# stratify=y forces the proportion of classes to remain constant
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, stratify=y, random_state=42
)

# Now, the ratio of 0s and 1s in y_train matches the original y.

Handling Time-Series and Temporal Dependencies

Standard random splitting fails completely when data points are dependent on time. In time-series forecasting, you cannot train on future data and predict the past. If you shuffle data that contains temporal order, you introduce 'look-ahead bias,' which makes the model artificially accurate because it has effectively seen the future. For these use cases, we must use chronological splitting: the training set must consist of data from the beginning of the timeline, and the validation and test sets must follow sequentially. This ensures that the model is tested on its ability to forecast future events given only the history available at that moment. This is a critical distinction in finance, sensor monitoring, and climate modeling, where the goal is to predict the next step in a sequence. Failing to respect the temporal order creates an evaluation that is useless for any real-world predictive application.

import numpy as np

# Time-series data is already ordered chronologically
# We take the first 70% for training, next 15% for val, last 15% for test
n = len(X)
train_end = int(0.7 * n)
val_end = int(0.85 * n)

# No shuffling allowed
X_train = X[:train_end]
X_val = X[train_end:val_end]
X_test = X[val_end:]
# Model learns history to predict the future.

Key points

  • A training set is used to update model parameters during the learning phase.
  • The validation set serves as an independent dataset for tuning hyperparameters and model selection.
  • The test set must remain untouched until the final evaluation to ensure an unbiased performance report.
  • Overfitting occurs when a model performs exceptionally on training data but fails to generalize to new, unseen data.
  • Data shuffling is crucial to prevent structural bias in datasets that are ordered by external factors.
  • Stratification preserves class proportions across all data splits, which is vital for imbalanced datasets.
  • Temporal data requires chronological splitting to avoid look-ahead bias and ensure realistic evaluation.
  • Data leakage occurs when information from the validation or test sets inadvertently influences the model training process.

Common mistakes

  • Mistake: Including validation data in the training phase. Why it's wrong: It causes data leakage, leading to an over-optimistic estimate of model performance. Fix: Strictly partition data before training begins and never allow the model to see the validation set during gradient updates.
  • Mistake: Performing feature scaling (e.g., standardization) on the entire dataset at once. Why it's wrong: Calculating the mean and variance of the entire dataset reveals information from the test set to the training process. Fix: Fit scalers only on the training set and transform the test/validation sets using those parameters.
  • Mistake: Using a simple random split for time-series data. Why it's wrong: Future information leaks into the past, violating the temporal nature of the data. Fix: Use a sequential split or a sliding window cross-validation approach.
  • Mistake: Treating the test set as a validation set for hyperparameter tuning. Why it's wrong: The test set should remain unseen until the very end; if you tune hyperparameters based on it, you are effectively training on it. Fix: Use a dedicated validation set for tuning and only touch the test set for the final evaluation.
  • Mistake: Ignoring the distribution shift between splits. Why it's wrong: If the training set contains categories or features absent in the test set, the model cannot generalize. Fix: Use stratified splitting to ensure target class distributions are consistent across all partitions.

Interview questions

What is the primary purpose of splitting a dataset into training, validation, and test sets in machine learning?

The primary purpose of this split is to ensure the model generalizes well to unseen data rather than just memorizing the training set. The training set is used to fit the model parameters, while the validation set is used to tune hyperparameters and perform model selection without overfitting. Finally, the test set acts as an unbiased evaluation of the final model's performance. By keeping these sets separate, we prevent information leakage, which would otherwise lead to overly optimistic performance estimates and poor real-world application.

Why do we need a separate validation set if we already have a test set?

The validation set is critical because we often make multiple decisions while building a model, such as choosing the learning rate, the depth of a tree, or the number of neurons in a hidden layer. If we used the test set to tune these hyperparameters, we would essentially be training the model on the test set, leading to data leakage. The validation set allows us to optimize our model architecture iteratively. Once we have locked in our final model, we use the test set exactly once to report the final expected error.

What is the consequence of having a test set that is too small?

A test set that is too small leads to high variance in the performance evaluation. If the set is small, the calculated error becomes highly sensitive to which specific data points ended up in the set, making the estimate statistically unreliable. This means the evaluation metrics, such as accuracy or mean squared error, might not accurately reflect how the model will perform on the true underlying population. A larger test set provides a more representative sample, yielding confidence intervals that are narrower and more trustworthy for final deployment decisions.

Compare a simple train-test split with K-Fold Cross-Validation. When would you prefer one over the other?

A simple train-test split is computationally efficient and ideal when the dataset is very large, as a single pass is sufficient for evaluation. However, K-Fold Cross-Validation is superior for smaller datasets because it ensures every data point is used for both training and validation across different folds. By averaging the results over K iterations, Cross-Validation provides a more robust and less biased estimate of model performance. Use a simple split for massive data to save time, but use K-Fold for smaller datasets to maximize utility and statistical reliability.

What is 'data leakage' in the context of splitting, and how can a developer inadvertently cause it?

Data leakage occurs when information from outside the training set creeps into the model building process, leading to unrealistically high performance. A common mistake is performing feature scaling or normalization on the entire dataset before splitting. If you calculate the mean or variance of the entire set, information about the distribution of the test set flows into the training phase. The correct approach is to split first, then fit the scaler on the training set only, and apply those transformation parameters to both the validation and test sets.

In time-series forecasting, why is a random shuffle split inappropriate, and what technique should be used instead?

In time-series analysis, data points are temporally dependent; the past influences the future. If you use a random shuffle, you risk 'look-ahead bias,' where the model uses future data points to predict the past. To avoid this, we use a chronological split or 'sliding window' approach. For example, you train on data from months 1 through 6, validate on month 7, and test on month 8. This preserves the temporal order, ensuring that the model is evaluated on its ability to forecast future events based strictly on historical context, which is how it will function in production.

All Machine Learning interview questions →

Check yourself

1. What is the primary purpose of holding out a test set that is separate from the validation set?

  • A.To increase the total number of samples available for gradient descent training.
  • B.To provide an unbiased assessment of the model's final performance on unseen data.
  • C.To allow the model to adjust its hyperparameters multiple times during the final phase.
  • D.To reduce the computational cost of training by ignoring irrelevant data points.
Show answer

B. To provide an unbiased assessment of the model's final performance on unseen data.
The test set provides a final, objective metric of generalization. Option 0 is wrong because data used for testing is removed from training; option 2 describes validation, not testing; option 3 is incorrect as testing adds complexity, not cost savings.

2. If you are performing hyperparameter tuning using cross-validation, where should you perform data augmentation?

  • A.On the entire original dataset before any splits are made.
  • B.Only on the validation folds to improve model sensitivity.
  • C.On the training folds during each iteration of cross-validation.
  • D.Only on the final test set to ensure robustness.
Show answer

C. On the training folds during each iteration of cross-validation.
Augmentation is part of the training pipeline. Applying it before splitting (option 0) causes data leakage. Applying it to validation/test sets (options 1 and 3) corrupts the evaluation metric because the model shouldn't be tested on generated artificial samples.

3. Why is stratified sampling preferred over simple random sampling when splitting a dataset for classification?

  • A.It guarantees that the minority class is represented in every split in the same proportion as the original.
  • B.It significantly reduces the time required for the model to converge during training.
  • C.It forces the model to ignore noisy samples that might exist in the training set.
  • D.It converts a multiclass classification problem into a series of binary classification tasks.
Show answer

A. It guarantees that the minority class is represented in every split in the same proportion as the original.
Stratification ensures label consistency. It doesn't affect convergence speed (1), doesn't filter noise (2), and is not a methodology for problem transformation (3).

4. You observe that your model performs exceptionally well on the training set but poorly on the validation set. What should you conclude regarding the split?

  • A.The validation set is too small to provide a statistically significant result.
  • B.The split has resulted in a high variance scenario, likely due to overfitting.
  • C.The random seed used for the split was mathematically invalid.
  • D.The training set contains more outliers than the validation set.
Show answer

B. The split has resulted in a high variance scenario, likely due to overfitting.
This is a classic signature of overfitting. Small sample size (0) is a separate issue; random seeds are never 'invalid' (2); outlier density (3) doesn't typically cause this specific gap in performance compared to model complexity.

5. When working with a dataset where each record represents a specific user, why is it crucial to use 'group-aware' splitting?

  • A.To ensure the model learns user-specific biases instead of global patterns.
  • B.To increase the speed of the data loading pipeline.
  • C.To prevent data leakage by ensuring all records for a specific user stay in the same partition.
  • D.To force the model to categorize users into demographic segments automatically.
Show answer

C. To prevent data leakage by ensuring all records for a specific user stay in the same partition.
If records from the same user appear in both training and testing, the model might 'memorize' the user instead of learning features. This is not for speed (1), nor for creating biases (0), nor for demographic segmentation (3).

Take the full Machine Learning quiz →

← PreviousML Overview — Supervised, Unsupervised, ReinforcementNext →Bias-Variance Tradeoff

Machine Learning

35 lessons, free to read.

All lessons →

Track your progress

Sign in to mark lessons done, score quizzes and keep notes.

Open in the app