AI & Machine Learning

Data Leakage in Machine Learning: 10 Mistakes That Destroy Your Model

Python Docker Machine Learning Pandas Scikit-learn Data Science Statistics Local AI Feature Engineering Cross-validation
1,468 words Includes Code
Machine Learning Data Leakage warning showing 4 types: target leakage, train/test contamination, preprocessing leakage, and temporal leakage
Key Takeaway: Data leakage occurs when your model accidentally uses information that wouldn't be available at prediction time. It creates deceptively high training metrics that collapse in production. The fix: split your data first, preprocess on training data only, and never peek at test data during development.

Data Leakage in Machine Learning: 10 Mistakes That Destroy Your Model

Your model achieves 99% accuracy on the test set. You deploy it. Real-world accuracy: 60%.

What happened? Most likely: data leakage.

Data leakage is one of the most dangerous problems in machine learning because it is invisible. Your metrics look great. Your model learns patterns that exist in your training data but will never exist in production.

This article explains the 10 most common data leakage mistakes, shows Python examples of each, and teaches you how to prevent them.

4 types of ML data leakage: Target Leakage, Train/Test Contamination, Preprocessing Leakage, and Temporal Leakage with prevention principles

What is Data Leakage?

Data leakage happens when information from outside the training dataset is used to create the model. The model learns shortcuts that work on your test set but fail in the real world.

IBM defines it as: "Information that would not be available at prediction time leaking into the training process."

The four main types:

Type Description Detection Difficulty
Target Leakage Feature contains future target information Medium
Train/Test Contamination Test data influences training decisions Hard
Preprocessing Leakage Scaling/encoding fitted on full dataset Medium
Temporal Leakage Future data predicts the past Hard

The 10 Data Leakage Mistakes

Mistake #1: Splitting After Preprocessing

This is the most common mistake. Beginners preprocess the entire dataset, then split into train/test.

# ❌ WRONG: Preprocess before split
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# Combines train and test information
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)  # Uses ALL data

X_train, X_test, y_train, y_test = train_test_split(
    X_scaled, y, test_size=0.2
)
# ✅ CORRECT: Split first, then preprocess
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2
)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # Only training data
X_test_scaled = scaler.transform(X_test)  # Don't fit!
⚠️ Why This Matters: When you fit the scaler on the full dataset, the test set's mean and standard deviation influence the scaling parameters. Your test set is no longer truly unseen.

Mistake #2: Target Leakage Through Features

Target leakage occurs when a feature contains information that directly or indirectly reveals the target variable.

# ❌ WRONG: Feature contains future target info
import pandas as pd

# Predicting if patient has diabetes
df = pd.DataFrame({
    'age': [45, 52, 38, 61],
    'weight': [80, 95, 72, 88],
    'hba1c_level': [8.2, 9.1, 5.4, 7.8],  # This IS the diagnosis!
    'has_diabetes': [1, 1, 0, 1]
})

# hba1c_level directly indicates diabetes
# Model learns this correlation, not real prediction
# ✅ CORRECT: Remove features that reveal the target
df_clean = df.drop(columns=['hba1c_level'])

# Use features that would be available BEFORE diagnosis
# age, weight, family_history, BMI, etc.

Mistake #3: Data Leakage in Cross-Validation

Cross-validation should simulate production. If preprocessing leaks across folds, your CV scores are unreliable.

# ❌ WRONG: Preprocess before cross-validation
from sklearn.model_selection import cross_val_score
from sklearn.pipeline import Pipeline

# Leakage: scaler sees all folds
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

scores = cross_val_score(model, X_scaled, y, cv=5)
# ✅ CORRECT: Use a Pipeline
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

# Pipeline preprocesses within each fold
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('model', RandomForestClassifier())
])

scores = cross_val_score(pipeline, X, y, cv=5)

Mistake #4: Temporal Leakage with Random Split

Time-series data must be split chronologically, not randomly.

# ❌ WRONG: Random split on time-ordered data
df = pd.DataFrame({
    'date': pd.date_range('2024-01-01', periods=1000),
    'feature_1': range(1000),
    'target': [0,1]*500
})

# Random split mixes past and future
X_train, X_test, y_train, y_test = train_test_split(
    df[['feature_1']], df['target'], test_size=0.2
)
# ✅ CORRECT: Time-based split
train_size = int(len(df) * 0.8)

# Train on past, test on future
X_train = df[['feature_1']].iloc[:train_size]
X_test = df[['feature_1']].iloc[train_size:]
y_train = df['target'].iloc[:train_size]
y_test = df['target'].iloc[train_size:]

Mistake #5: Including ID Columns

Unique identifiers can cause leakage if they correlate with the target.

# ❌ WRONG: ID column leaks information
df = pd.DataFrame({
    'patient_id': [1001, 1002, 1003, 1004],
    'feature_1': [0.5, 0.8, 0.3, 0.9],
    'target': [1, 1, 0, 1]
})

# patient_id might accidentally correlate with target
# ✅ CORRECT: Remove ID columns
X = df.drop(columns=['patient_id', 'target'])

Mistake #6: Leakage in Feature Engineering

Feature engineering must use only training data statistics.

# ❌ WRONG: Compute mean using all data
mean_age = df['age'].mean()  # Includes test data!
df['age_normalized'] = df['age'] / mean_age
# ✅ CORRECT: Compute statistics from training data only
mean_age = X_train['age'].mean()  # Only training data
X_train['age_normalized'] = X_train['age'] / mean_age
X_test['age_normalized'] = X_test['age'] / mean_age

Mistake #7: Data Duplication Across Splits

Duplicate rows in both train and test sets create leakage.

# ❌ WRONG: Duplicates across splits
df = pd.DataFrame({
    'feature': [1, 2, 3, 1, 2, 4],  # Rows 0,3 and 1,4 are duplicates
    'target': [0, 0, 1, 0, 0, 1]
})

X_train, X_test, y_train, y_test = train_test_split(
    df[['feature']], df['target'], test_size=0.3
)
# ✅ CORRECT: Remove duplicates before splitting
df_deduped = df.drop_duplicates()
X_train, X_test, y_train, y_test = train_test_split(
    df_deduped[['feature']], df_deduped['target'], test_size=0.3
)

Mistake #8: Target Encoding Before Split

Target encoding uses the target variable to create features. Doing this before splitting leaks the target into features.

# ❌ WRONG: Target encoding before split
from category_encoders import TargetEncoder

# Uses target information from all data
encoder = TargetEncoder()
X_encoded = encoder.fit_transform(X, y)
# ✅ CORRECT: Target encoding within CV folds
from sklearn.model_selection import KFold

kf = KFold(n_splits=5, shuffle=False)
for train_idx, val_idx in kf.split(X):
    X_train_fold = X.iloc[train_idx]
    y_train_fold = y.iloc[train_idx]
    
    encoder = TargetEncoder()
    X_train_encoded = encoder.fit_transform(X_train_fold, y_train_fold)
    X_val_encoded = encoder.transform(X.iloc[val_idx])

Mistake #9: Leakage Through Test Set Exploration

Peeking at test data influences your decisions about preprocessing, feature selection, or model selection.

# ❌ WRONG: Exploring test set before final evaluation
X_train, X_test, y_train, y_test = train_test_split(X, y)

# Looking at test distribution
print(X_test.describe())  # This influences your decisions!

# Adjusting preprocessing based on test statistics
# Using test set for hyperparameter tuning
# ✅ CORRECT: Use validation set for exploration
X_train, X_temp, y_train, y_temp = train_test_split(X, y, test_size=0.3)
X_val, X_test, y_val, y_test = train_test_split(X_temp, y_temp, test_size=0.5)

# Explore validation set, not test set
print(X_val.describe())  # OK to explore

# Final test set is used ONLY once at the very end

Mistake #10: Aggregate Statistics Before Split

Computing group statistics using the full dataset before splitting creates leakage.

# ❌ WRONG: Group statistics using all data
df['dept_avg'] = df.groupby('department')['target'].transform('mean')

# This directly leaks the target into a feature!
# ✅ CORRECT: Compute group statistics from training data only
dept_means = X_train.join(y_train).groupby('department')['target'].mean()

X_train['dept_avg'] = X_train['department'].map(dept_means)
X_test['dept_avg'] = X_test['department'].map(dept_means)

How to Detect Data Leakage

Sign What It Means Action
Test accuracy >> Production accuracy Model learned test-specific patterns Review preprocessing pipeline
Feature importance shows unexpected columns Leaky features dominating Remove suspicious features
AUC > 0.99 on test Too good to be true Check for target leakage
Cross-validation scores vary widely Inconsistent leakage across folds Use Pipeline for preprocessing

Prevention Checklist

Data Leakage Prevention Checklist:Split First - [ ] Split data before any preprocessing - [ ] Use time-based splits for temporal data - [ ] Remove duplicates before splitting ✅ Preprocess Correctly - [ ] Fit scalers on training data only - [ ] Fit encoders on training data only - [ ] Use sklearn Pipeline for cross-validation ✅ Feature Engineering - [ ] Remove ID columns - [ ] Check for target leakage in features - [ ] Compute statistics from training data only ✅ Evaluation - [ ] Never touch test set during development - [ ] Use validation set for tuning - [ ] Final evaluation on test set only once ✅ Verification - [ ] Check test metrics vs production metrics - [ ] Analyze feature importances - [ ] Verify no duplicates across splits

Try It Yourself

Ready to build robust ML pipelines?

Further Reading

💬 Discuss this topic on BestWordz Community

Conclusion

Data leakage is silent. It gives you great metrics and terrible production performance. The only way to catch it is to understand the patterns.

The fundamental principle is simple: never let information from outside the training set influence your model.

Split your data first. Preprocess on training data only. Use Pipeline for cross-validation. Keep your test set locked away until final evaluation.

The 10 mistakes in this article are common, but they are all preventable. Add the prevention checklist to your ML workflow and check it before every model deployment.

Your model's test accuracy means nothing if it leaked data. Build systems that prevent leakage by design.

Continue Learning: Data Science Pipeline

From data to insights

  1. The 10-Stage Data Science Roadmap
  2. What Is a Vector?
  3. What Is Prompt Engineering?
  4. Data Leakage in Machine Learning: 10 Mistakes That Destroy Your Model (this article)
  5. Keyword Search vs Semantic Search

💬 Discuss on BestWordz Community

Join the conversation about Python, Docker, Machine Learning on the BestWordz Community forum.

Visit Forum →