Preventing Data Leakage: Validation Splits and Common Traps Explained

Last updated: ⏱ Reading time: ~14 minutes

AI-assisted guide Curated by Norbert Sowinski

Share this guide:

Diagram-style illustration of machine-learning data leakage showing train, validation, and test boundaries, preprocessing pipelines, grouped and temporal splits, forbidden information flow, and trustworthy model evaluation

Data leakage is one of the easiest ways to build a machine-learning model that appears impressive during experimentation and disappoints as soon as it encounters genuinely unseen data.

The dangerous part is that leakage does not always look like an obvious programming error. The code can run correctly, cross-validation can look excellent, and every metric can improve. The problem is methodological: information crossed a boundary that will not be crossed when the model is used in production.

Preventing leakage therefore starts before choosing an algorithm. You need to define what will be known at prediction time, which observations are truly independent, and what future deployment should look like.

The core question

For every feature and preprocessing step, ask: “Would this information be available, in exactly this form, at the moment the production model has to make the prediction?”

1. What data leakage actually means

Leakage occurs when model development benefits from information that would not legitimately be available for a new production prediction.

Leakage-safe information boundary (diagram)

Machine-learning data leakage boundary showing raw data divided into training, validation, and final test sets, preprocessing and feature engineering fitted only within training data, allowed information flowing toward validation and test transformation, and forbidden reverse information flow from held-out data

Leakage can enter through several routes:

Leakage is different from ordinary overfitting

Overfitting means learning patterns that do not generalize well. Leakage means the experiment itself provided information that should not have been available.

The two can coexist, but leakage is particularly dangerous because even a simple model can achieve unrealistic scores when the validation design is contaminated.

2. Define the prediction boundary before splitting data

A correct split reflects the real prediction task. Before calling train_test_split(), write down what the model is supposed to do.

Define these five things

  1. What entity receives a prediction?
  2. At what moment is the prediction made?
  3. Which information exists at that moment?
  4. Which entities can appear repeatedly?
  5. What kind of unseen data will production present?

Example: customer churn

Suppose the model predicts on January 1 whether a customer will churn during the next 90 days.

Features available on January 1 may be legitimate:

Features created afterward are not:

Availability is not the same as existence

A field may exist today in a historical database while still being unavailable at the historical prediction time. Build features according to when they become known, not simply according to whether the final database contains them.

3. Preprocessing leakage: split before you fit

Many preprocessing operations learn statistics from data. Those statistics are model parameters in everything but name.

Common learned preprocessing

Incorrect: transform before splitting

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

scaler = StandardScaler()

X_scaled = scaler.fit_transform(X)

X_train, X_test, y_train, y_test = train_test_split(
    X_scaled,
    y,
    test_size=0.2,
    random_state=42
)

The scaler has already seen the mean and standard deviation of observations that later become the test set.

Correct: split first

from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42
)

scaler = StandardScaler()

X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

The same principle applies to imputation:

from sklearn.impute import SimpleImputer

imputer = SimpleImputer(strategy="median")

X_train_imp = imputer.fit_transform(X_train)
X_test_imp = imputer.transform(X_test)

Think in terms of fit and transform

Held-out data may usually pass through a transformation that was already fitted on training data. It should not normally participate in learning that transformation.

4. Target leakage and post-outcome features

Target leakage occurs when a feature directly or indirectly reveals the outcome.

Obvious examples

Prediction Leaky feature
Customer churn Cancellation date
Loan default Collections status recorded after default
Fraud detection Final investigator decision
Hospital outcome Treatment performed after diagnosis
Delivery delay Actual delivery timestamp

Indirect leakage is harder

A feature may not literally contain the target but can encode a downstream process that only occurs because the outcome has already happened.

Examples:

Audit feature timestamps

For important models, create a feature-availability table:

feature                 available_at_prediction
------------------------------------------------
account_age             yes
current_plan            yes
past_30d_usage          yes
cancellation_reason     no
refund_amount           no
retention_result        no

Feature provenance is often more useful for finding leakage than looking at model coefficients.

Extremely predictive features deserve investigation

A feature producing almost perfect separation may be genuinely excellent, but it should trigger questions:

5. Random, stratified, grouped, or temporal split?

Validation-split decision tree (diagram)

Machine-learning validation split decision tree choosing between random train-test splitting, stratified classification splits, grouped validation for repeated entities, and chronological time-series validation based on independence, class balance, entity repetition, and temporal prediction requirements

Random split

A random split is appropriate when rows are sufficiently independent and future production observations come from roughly the same process.

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42
)

Stratified split

Classification datasets with uncommon classes may benefit from preserving approximate class proportions.

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y
)

Stratification helps class balance. It does not prevent entity or temporal leakage.

Grouped validation

Use groups when several rows belong to the same logical entity and the production task requires generalizing beyond that entity.

Examples:

from sklearn.model_selection import GroupKFold

cv = GroupKFold(n_splits=5)

for train_idx, valid_idx in cv.split(X, y, groups=customer_id):
    X_train = X.iloc[train_idx]
    X_valid = X.iloc[valid_idx]

The important property is that one group does not appear in both the training and held-out portion of a fold.

Temporal validation

When production predicts future outcomes from past information, preserve chronological order instead of randomly mixing observations.

train = df[df["timestamp"] < "2026-01-01"]
test = df[df["timestamp"] >= "2026-01-01"]

For repeated temporal evaluation, use a time-aware splitting strategy.

6. Duplicate and entity leakage

A random splitter knows nothing about the semantic relationship between rows.

Exact duplicates

If identical observations appear in both train and test sets, a model may effectively be evaluated on records it has already seen.

duplicates = df.duplicated().sum()

print("Duplicate rows:", duplicates)

Investigate duplicates before splitting and decide whether they represent legitimate repeated events or accidental copies.

Near-duplicates

Images, text, product records, or documents may have slightly modified versions that remain essentially the same example.

Examples include:

Entity memorization

Suppose you predict future purchases but randomly split transactions. The model may see earlier and later transactions from the same customer in both partitions.

That may be correct if production predicts another event for an existing known customer. It is misleading if the stated goal is generalization to completely new customers.

The split defines the question

“Can we predict another event for a known customer?” and “Can we generalize to a customer never seen before?” are different experiments and often require different validation splits.

7. Temporal leakage and future information

Time creates some of the most subtle leakage problems because a feature can be historically valid but still calculated using future observations.

Bad: rolling feature using future data

Imagine predicting tomorrow's demand while computing a centered moving average containing values from both before and after the prediction timestamp.

The feature looks mathematically reasonable, but production cannot know tomorrow's future neighbors.

Use past-only windows

df = df.sort_values("timestamp")

df["past_7d_average"] = (
    df["value"]
      .shift(1)
      .rolling(window=7)
      .mean()
)

The shift(1) makes the example explicitly exclude the current outcome from its historical window.

TimeSeriesSplit

from sklearn.model_selection import TimeSeriesSplit

cv = TimeSeriesSplit(
    n_splits=5
)

for train_idx, valid_idx in cv.split(X):
    X_train = X.iloc[train_idx]
    X_valid = X.iloc[valid_idx]

Time-aware splitting trains on earlier observations and evaluates on later observations instead of reversing the production direction.

Consider a gap

Some applications require separation between training and validation periods because labels mature slowly or features near the boundary share information.

cv = TimeSeriesSplit(
    n_splits=5,
    gap=7
)

Whether a gap is required depends on the meaning and spacing of the observations.

Random cross-validation can answer the wrong question

For a forecasting or future-event problem, random folds often estimate performance under random interpolation between historical observations, not genuine forward-looking production performance.

8. Feature selection, target encoding, and oversampling traps

Feature selection before cross-validation

Suppose you select the 20 features most correlated with the target using the complete dataset and then run cross-validation.

Validation labels already influenced which features were selected.

Feature selection must occur independently inside each training fold.

Target encoding

A target-encoded categorical feature may replace a category with the average label associated with that category.

Calculating those averages using the complete dataset leaks validation labels directly into features.

Use fold-aware or out-of-fold target encoding and ensure the validation observation's own label does not influence its encoded value.

Oversampling

Oversampling the minority class before splitting can create synthetic or repeated observations closely related to samples that later appear in validation.

The safe conceptual order is:

  1. Define the validation split.
  2. Take only the training portion.
  3. Fit the resampling strategy there.
  4. Train the model.
  5. Evaluate on untouched validation observations.

Dimensionality reduction

PCA and similar learned transformations also need the training boundary. Fit them inside each fold rather than once on the full feature matrix.

Global feature engineering

Aggregates can leak even when they do not directly use the target.

Example:

customer_total_orders =
    count of every order the customer ever places

If the prediction occurs halfway through that customer's history, the final lifetime total includes future behavior.

The correct feature is closer to:

orders_before_prediction_time =
    count of orders known before the prediction timestamp

9. Protect the final test set

A held-out test set estimates performance on data that did not influence model development.

That purpose disappears if you check the test result after every experiment.

Test-set contamination through decision making

Imagine this workflow:

  1. Train model A.
  2. Check test accuracy.
  3. Add a feature because test accuracy was disappointing.
  4. Check test accuracy again.
  5. Change the algorithm.
  6. Change the classification threshold.
  7. Repeat until the test score looks good.

The test set has become a validation set. Its feedback shaped the model.

Better workflow

  1. Set aside the final test set.
  2. Develop using training data plus cross-validation or a validation set.
  3. Select preprocessing, features, model family, and hyperparameters there.
  4. Freeze the decision process.
  5. Evaluate on the final test set.

Hyperparameter tuning belongs inside validation

from sklearn.model_selection import GridSearchCV

search = GridSearchCV(
    estimator=pipeline,
    param_grid=params,
    cv=5,
    scoring="roc_auc"
)

search.fit(X_train, y_train)

final_score = search.score(
    X_test,
    y_test
)

The test set is not passed into the grid search.

Nested cross-validation

When data is limited and you need an especially careful estimate while tuning many hyperparameters, nested cross-validation can separate model selection from performance estimation.

It is more computationally expensive, so it is not automatically required for every project.

10. Build leakage-safe validation pipelines

Leakage-safe model evaluation flow (diagram)

Leakage-safe machine-learning evaluation workflow showing production prediction definition, grouped or temporal split selection, isolated final test set, training-fold preprocessing, imputation, scaling, feature selection and model fitting, validation scoring, hyperparameter selection, refitting on development data, and one final untouched test evaluation

Use Pipeline for learned transformations

from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

pipeline = Pipeline([
    (
        "imputer",
        SimpleImputer(strategy="median")
    ),
    (
        "scaler",
        StandardScaler()
    ),
    (
        "model",
        LogisticRegression(max_iter=1000)
    )
])

When the pipeline is evaluated through cross-validation, each training fold fits its own imputer and scaler.

Cross-validation

from sklearn.model_selection import cross_val_score

scores = cross_val_score(
    pipeline,
    X,
    y,
    cv=5,
    scoring="roc_auc"
)

print(scores)
print(scores.mean())

For grouped observations, replace ordinary folds with the appropriate grouped splitter and supply the group labels.

from sklearn.model_selection import GroupKFold
from sklearn.model_selection import cross_val_score

cv = GroupKFold(n_splits=5)

scores = cross_val_score(
    pipeline,
    X,
    y,
    cv=cv,
    groups=customer_id,
    scoring="roc_auc"
)

For time-dependent data

from sklearn.model_selection import TimeSeriesSplit

cv = TimeSeriesSplit(
    n_splits=5,
    gap=7
)

scores = cross_val_score(
    pipeline,
    X,
    y,
    cv=cv,
    scoring="neg_mean_absolute_error"
)

Audit the entire information path

Before trusting the score, review every stage:

Validate the deployment scenario, not the dataset format

The best split is the one that reproduces the information boundary the model will face after deployment. Rows in the same CSV file are not necessarily independent observations.

11. Copy/paste data-leakage checklist

Data leakage prevention checklist

Prediction definition
- Define exactly what the model predicts.
- Define the prediction timestamp.
- Define what information exists at prediction time.
- Define whether production predicts known or unseen entities.
- Define whether predictions concern future events.
- Document the intended production population.

Raw data
- Preserve raw input.
- Record data extraction timestamps.
- Inspect duplicate rows.
- Inspect near-duplicates where relevant.
- Identify repeated entities.
- Identify historical snapshots of the same entity.
- Review joins for accidental future information.
- Review label-generation logic.

Feature availability
- Record when every important feature becomes available.
- Remove post-outcome features.
- Remove target-derived features.
- Investigate suspiciously predictive fields.
- Check whether operational workflow states occur after the target.
- Check whether aggregate features contain future observations.
- Ensure rolling statistics use past-only windows.
- Verify external datasets were historically available at prediction time.

Initial splitting
- Choose the split before fitting preprocessing.
- Use random splitting only when observations are sufficiently independent.
- Use stratification when class balance requires it.
- Use grouped splitting when entities repeat.
- Use temporal splitting for future prediction.
- Consider a gap between train and validation when the domain requires it.
- Document the reason for the chosen validation design.

Duplicates and entities
- Prevent exact duplicates from crossing the validation boundary.
- Investigate near-duplicate content.
- Keep repeated measurements together when production requires entity-level generalization.
- Keep images of the same subject together where appropriate.
- Keep transactions from the same customer together where appropriate.
- Keep documents derived from the same original source together where appropriate.
- Check whether identifier-like features allow memorization.

Preprocessing
- Split before fitting imputers.
- Fit imputation statistics on training data only.
- Fit scalers on training data only.
- Fit PCA on training data only.
- Fit learned encoders on training data only.
- Fit vocabulary creation inside the training boundary.
- Fit rare-category grouping inside the training boundary.
- Transform validation and test data using already fitted training transformers.

Feature selection
- Do not select features using the full dataset.
- Keep supervised feature selection inside cross-validation.
- Keep dimensionality reduction inside cross-validation.
- Keep variance or frequency rules inside the correct training boundary when they depend on data.
- Investigate perfect or nearly perfect predictors.

Target encoding
- Do not calculate target means using validation labels.
- Use fold-aware or out-of-fold encoding.
- Prevent a row's own label from influencing its encoded feature where required.
- Handle unseen categories safely.

Resampling
- Do not oversample the full dataset before splitting.
- Apply oversampling only to training folds.
- Do not generate synthetic validation observations from training neighbors.
- Evaluate on untouched natural validation distributions.
- Keep resampling inside the evaluation pipeline when possible.

Temporal features
- Sort observations by time.
- Confirm timestamps reflect when information became available.
- Avoid future values in rolling statistics.
- Shift target-related aggregates when necessary.
- Avoid backward filling from future observations into past predictions.
- Avoid fitting global temporal statistics using future periods.
- Use chronological validation for future prediction.
- Consider concept and data drift.

Cross-validation
- Choose cross-validation that matches the deployment scenario.
- Use grouped folds for repeated entities when appropriate.
- Use time-aware folds for chronological prediction.
- Keep preprocessing inside each fold.
- Keep feature selection inside each fold.
- Keep resampling inside each fold.
- Tune hyperparameters using validation folds, not the final test set.

Final test set
- Set aside the final test set before model development.
- Do not inspect test results after every experiment.
- Do not choose features based on final test performance.
- Do not tune hyperparameters on final test results.
- Do not choose the classification threshold on the final test set.
- Do not choose preprocessing based on the final test set.
- Evaluate the frozen modeling approach on the final test set.
- Document any decision made after seeing final test performance.

Pipeline
- Put learned preprocessing in a Pipeline.
- Use ColumnTransformer for different feature types where appropriate.
- Place imputation inside the pipeline.
- Place scaling inside the pipeline.
- Place encoding inside the pipeline.
- Place feature selection inside the pipeline.
- Evaluate the complete pipeline with cross-validation.
- Persist the same fitted pipeline used for production prediction.

Validation quality
- Compare validation distributions with expected production data.
- Check performance by time period.
- Check performance by entity group.
- Check performance by important business segment.
- Check whether validation examples are unrealistically similar to training data.
- Compare validation and production feature availability.
- Investigate unexpectedly high validation scores.

Before deployment
- Reconstruct one prediction exactly as production will see it.
- Confirm every required feature exists at that moment.
- Confirm no feature is calculated from future information.
- Confirm preprocessing uses only fitted training parameters.
- Confirm the model does not require labels at inference time.
- Confirm the validation split matches the expected deployment population.
- Record known limitations and leakage risks.

12. FAQ

What is data leakage in machine learning?

Data leakage occurs when information unavailable during real production prediction influences training, preprocessing, model selection, or evaluation. The result is usually an overly optimistic validation score.

Should I split data before preprocessing?

Yes for preprocessing that learns from observations. Split first, then fit imputers, scalers, feature selectors, encoders, PCA, and similar transformations on training data only. Apply the fitted transformation to validation and test data.

When should I use GroupKFold?

Use grouped validation when multiple samples belong to the same logical entity and those groups should remain separate across training and validation. Common examples include repeated measurements from patients, transactions from customers, readings from devices, and several samples derived from one subject.

Why is random splitting dangerous for time-series data?

Random splitting can place later observations in training and earlier observations in validation. A model can therefore learn from a future state that would not exist when making the historical prediction being evaluated.

Does stratification prevent leakage?

No. Stratification helps preserve class proportions. It does not prevent the same customer, patient, device, document family, or future time period from leaking across the split.

Can I keep checking the test set while developing the model?

Repeated test-set feedback influences feature, model, threshold, and hyperparameter decisions. At that point the test set becomes part of model development. Use validation or cross-validation during iteration and preserve a separate final evaluation set.

Key terms (quick glossary)

Data leakage
Information unavailable under the intended production prediction conditions influencing model development or evaluation.
Target leakage
Leakage caused by a feature that directly or indirectly contains information about the outcome that would not be available when the prediction is made.
Training set
Data used to fit model parameters and learned preprocessing transformations.
Validation set
Held-out observations used during model development to compare configurations, features, hyperparameters, or thresholds.
Test set
Data reserved for final estimation of performance after the development process has been completed.
Cross-validation
A resampling procedure that repeatedly divides data into training and validation portions to estimate model performance and variability.
GroupKFold
A cross-validation strategy that keeps the same group from appearing in both training and validation portions of a fold.
TimeSeriesSplit
A cross-validation strategy for ordered data in which models train on earlier observations and evaluate on later observations.
Preprocessing leakage
Leakage introduced when statistics or transformations are learned using held-out observations.
Entity leakage
Leakage caused when related observations from the same underlying entity appear on both sides of a validation boundary.
Pipeline
A sequence of preprocessing transformers and an estimator that can be fitted and evaluated as one object, helping keep learned transformations within the appropriate training fold.
Prediction boundary
The point in time and information state defining exactly what the model is allowed to know when making a real prediction.

Found this useful? Share this guide: