Sitemap
Khawaja Muhammad Laeeq

Khawaja Muhammad Laeeq

AI & Full-Stack Developer. Writing about LLMs, Agentic AI, RAG, machine learning, modern web technologies and how to build reliable AI systems.🌐khawajalaeeq.me

Press enter or click to view image in full size

Data Leakage in Machine Learning: Why My Model Looked Almost Perfect

9 min readOct 24, 2026

--

Data Leakage in Machine Learning: Why My Model Looked Almost Perfect

One hidden feature pushed a machine learning model’s ROC-AUC to nearly 0.98. Here’s how a Python experiment exposed the problem — and why impressive ML metrics don’t always mean reliable predictions.

Imagine spending weeks building a machine learning model.

You clean your dataset. Handle missing values. Engineer features. Train your algorithm. Run your evaluation.

And then you see a result that makes everything feel worthwhile.

ROC-AUC: 0.978

Almost perfect.

You might assume your model has discovered something remarkable about the data. Perhaps your feature engineering was excellent. Maybe your algorithm identified relationships that simpler approaches missed.

But what if the model wasn’t actually learning to predict anything?

What if it already had access to the answer?

That is exactly what data leakage in machine learning can do.

It can make an average model appear exceptional, produce misleading evaluation metrics, and create a false sense of confidence before deployment.

To understand how dangerous this can be, I built a small, reproducible experiment using Python and Scikit-learn.

The results were revealing.

The Machine Learning Model That Looked Too Good

Let’s imagine we’re developing a customer churn prediction system for a subscription-based business.

The objective is straightforward.

We want to predict which customers are likely to cancel their subscriptions, ideally before they make that decision.

A useful model might analyze:

  • How frequently customers use the product.
  • Whether they have experienced failed payments.
  • How often they contact customer support.
  • Whether their activity has recently declined.

These features are reasonable because they might be available before a customer cancels.

For this experiment, I generated a synthetic dataset containing 2,400 customer records.

Each customer had three behavioral features:

  • usage_drop
  • failed_payments
  • support_requests

I also generated a binary target variable representing whether that customer churned.

Then I introduced one additional feature.

At first glance, it might seem harmless.

But it would completely change the model’s evaluation.

That feature was called:

post_outcome_flag

Unlike the legitimate behavioral variables, this feature was generated using the churn outcome itself.

In other words, it contained information about the answer the model was supposed to predict.

After training a Logistic Regression classifier using a chronological train-test split, the result was:

ROC-AUC: 0.9777

That is an impressive number.

Unfortunately, it was impressive for the wrong reason.

What Is Data Leakage in Machine Learning?

Data leakage occurs when information that should not legitimately be available during model training or prediction influences the model or its evaluation.

It often produces overly optimistic performance estimates.

The model may appear to generalize well, even though it relies on information that will not be available in the intended real-world prediction scenario.

One especially important type is target leakage.

Target leakage happens when a feature contains information derived from the variable the model is trying to predict, or from events that occur after the prediction point.

Consider a hospital model designed to predict whether a patient will be readmitted.

Suppose the training dataset includes a field populated only after a patient has been readmitted.

That field might correlate extremely strongly with the target.

The model could achieve remarkable validation scores simply by using it.

But when the hospital needs to predict readmission risk before discharge, that information doesn’t exist yet.

The model has learned a shortcut rather than a useful predictive relationship.

And the same problem appeared in my churn experiment.

How Target Leakage Made My Model Look Almost Perfect

The suspicious feature, post_outcome_flag, was generated directly from the simulated churn outcome, with a small amount of random noise.

It was deliberately designed to reproduce a common type of leakage: an outcome-related field entering a training dataset through a historical export or an incorrectly constructed feature pipeline.

Think about the difference between two customer attributes.

Failed payments last month: Information that may genuinely be available before cancellation.

Final account cancellation flag: Information that may only become available after cancellation has already happened.

The first could be a legitimate predictive feature.

The second would be inappropriate for a model intended to predict cancellation in advance.

The machine learning algorithm doesn’t inherently know that distinction.

It only knows that a particular feature helps it make accurate predictions.

If we provide information derived from the answer, the algorithm will use it.

That’s not a failure of Logistic Regression.

It’s a failure of how we defined the prediction problem.

The Experiment: What Happens When We Remove Data Leakage?

I trained two models using the same synthetic dataset and classifier.

The only meaningful difference was whether the leaked feature was included.

The results were:

ModelTest ROC-AUCModel with target leakage0.9777Model without target leakage0.7703

Removing a single contaminated feature reduced the ROC-AUC by approximately 0.207.

At first, that might look like a dramatic regression.

But consider what actually changed.

The first model had access to information derived from the outcome.

The second was restricted to legitimate behavioral features.

The second model wasn’t necessarily worse. Its evaluation was more trustworthy.

A score of 0.77 isn’t automatically good or bad. Whether it’s useful depends on the business problem, class distribution, costs of mistakes, and performance relative to simple baselines.

But unlike the inflated score, it tells us something meaningful about the predictive signal available in our chosen features.

That is a much better starting point for building a reliable machine learning system.

Reproducing Data Leakage in Python with Scikit-learn

Let’s reproduce the experiment using Python.

We’ll use NumPy to generate synthetic customer data and Scikit-learn to train and evaluate a Logistic Regression model.

First, import the required libraries.

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
rng = np.random.default_rng(17)n = 2400

Next, generate three legitimate behavioral features.

usage_drop = rng.normal(size=n)
failed_payments = rng.binomial(
1, 0.18, size=n
)
support_requests = rng.poisson(
1.2, size=n
)

We then construct simulated churn probabilities.

logit = (
-1.2
+ 1.25 * usage_drop
+ 1.1 * failed_payments
+ 0.24 * support_requests
)
probability = 1 / (1 + np.exp(-logit))y = rng.binomial(1, probability)

Now comes the important part.

We deliberately create a feature using the target variable.

post_outcome_flag = np.where(
rng.random(n) < 0.06,
1 - y,
y
)

This feature matches the outcome in approximately 94% of cases.

Of course it helps the model predict churn. It was created using the churn outcome.

Next, create two feature sets.

X_clean = np.column_stack([
usage_drop,
failed_payments,
support_requests
])
X_leaked = np.column_stack([
X_clean,
post_outcome_flag
])

Finally, train and evaluate both models.

split = 1800
for name, X in [
("With leakage", X_leaked),
("Without leakage", X_clean)
]:
model = LogisticRegression(
max_iter=1000
)
model.fit(
X[:split],
y[:split]
)
predictions = model.predict_proba(
X[split:]
)[:, 1]
auc = roc_auc_score(
y[split:],
predictions
)
print(f"{name}: {auc:.4f}")

The results:

With leakage: 0.9777
Without leakage: 0.7703

The experiment uses a fixed random seed to make its results reproducible with a compatible environment.

Get Khawaja Muhammad Laeeq’s stories in your inbox

Join Medium for free to get updates from this writer.

The observations are synthetic, and their order is used for the split; they do not represent an actual chronological customer history. This demonstrates target leakage, not a full production deployment.

Still, the lesson is clear.

We didn’t change the algorithm.

We didn’t increase model complexity.

We didn’t introduce advanced hyperparameter optimization.

We simply removed one feature that should never have been available.

And the apparent performance changed dramatically.

Why Train-Test Splits Don’t Always Prevent Data Leakage

A common misconception is that separating training and testing data automatically prevents leakage.

It doesn’t.

A train-test split prevents the model from directly fitting on the withheld observations.

But it cannot guarantee that every feature in those observations is legitimate.

In this experiment, the classifier was trained on the first 1,800 observations and tested on the remaining 600.

The model never fitted on those test observations.

Yet the evaluation was still contaminated.

Why?

Because the test feature matrix included a variable generated from the test outcomes.

The model could exploit the relationship even though the test observations were held out.

This highlights an important distinction:

Unseen test rows are not necessarily the same thing as a valid test of future predictions.

Before trusting an evaluation, we must consider when every feature became available and whether the validation setup represents the actual prediction task.

For further reading, Scikit-learn’s official documentation discusses data leakage and recommended machine learning practices.

Four Common Types of Data Leakage in Machine Learning

Target leakage isn’t the only way information can contaminate a machine learning pipeline.

Understanding the different forms of leakage is essential when building and evaluating models.

1. Target leakage

This occurs when features contain information about the outcome that would not be legitimately available at prediction time.

Examples include using final cancellation status to predict churn or a post-diagnosis field to predict a diagnosis before it happens.

The model appears highly accurate because the answer has effectively been revealed.

2. Data preprocessing leakage

Imagine standardizing your entire dataset before splitting it into training and testing subsets.

The scaling transformation uses statistics calculated from the test observations.

The model training process has therefore indirectly incorporated information from the evaluation set.

The same issue can occur during imputation, feature selection, and other preprocessing operations.

A safer approach is to fit preprocessing transformations on training data only.

3. Temporal leakage

Suppose you’re predicting tomorrow’s sales.

Your training dataset includes the total number of transactions recorded tomorrow.

That information is not available today.

Historical datasets can make this mistake difficult to notice because past and future values are already stored together.

Time-aware feature engineering and validation are essential for these tasks.

4. Group leakage

Consider a dataset containing several observations from the same person, customer, or organization.

If related records appear in both training and testing sets, a model might learn entity-specific patterns instead of general patterns.

Whether this invalidates evaluation depends on the real application.

For example, predicting future behavior for existing customers differs from predicting behavior for customers the model has never encountered.

The validation strategy should reflect that distinction.

How to Prevent Data Leakage in Machine Learning

Avoiding data leakage requires more than choosing a good algorithm.

It requires designing the entire machine learning pipeline around the intended prediction scenario.

Here are the practices I would prioritize.

Define when the prediction happens

Before selecting features, determine the exact point in time when your model will make predictions.

For churn prediction, are we predicting cancellation seven days ahead or thirty days ahead?

Any information created after that prediction point should be carefully examined.

Audit your features

For every feature, ask:

  • Where does this information originate?
  • When does it become available?
  • Is it derived from the target?
  • Would it exist during real-world inference?
  • Does its definition change between training and production?

These questions can reveal issues that model metrics alone will never identify.

Use Scikit-learn pipelines

Pipelines help ensure preprocessing is fitted in the correct training context.

For example:

from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
model = make_pipeline(
StandardScaler(),
LogisticRegression(max_iter=1000)
)
model.fit(
X_clean[:split],
y[:split]
)

This approach becomes especially valuable during cross-validation.

However, pipelines cannot automatically detect every form of leakage.

They won’t recognize that a particular database column contains future information unless we identify that problem ourselves.

Choose the right validation strategy

Random splitting isn’t always appropriate.

Time-series tasks may require chronological validation.

Datasets containing related records may require group-aware splitting.

Cross-validation should represent the actual deployment scenario rather than simply producing convenient scores.

Investigate surprisingly high model performance

Excellent results aren’t inherently suspicious.

But unexpectedly high scores deserve investigation.

Check whether:

  • Features contain information derived from the outcome.
  • Duplicate or near-duplicate observations cross data splits.
  • Preprocessing was fitted using evaluation data.
  • Features depend on future information.
  • The evaluation scenario matches production.

Sometimes the most useful debugging step is removing a suspicious feature and evaluating the model again.

Why Data Leakage Matters Beyond Model Accuracy

The consequences of leakage go beyond an inflated evaluation metric.

Imagine a business deploying a model that appeared exceptionally accurate during testing.

The company uses its predictions to allocate budgets, prioritize customers, or make operational decisions.

But when the system starts generating real predictions, some of the information it relied on during training is unavailable.

Performance deteriorates.

Teams lose confidence.

Business decisions become harder to justify.

And developers may spend days tuning algorithms when the real problem lies in the data pipeline.

That’s why machine learning engineering isn’t simply about training increasingly sophisticated models.

It also involves understanding the origin, availability, and reliability of the information those models consume.

The Real Lesson: A Lower Score Can Be a Better Result

At the beginning of this experiment, the model achieved an ROC-AUC of approximately 0.98.

It looked remarkably successful.

After removing the leaked feature, that score dropped to around 0.77.

If we focused exclusively on maximizing ROC-AUC, the first model would appear superior.

But its score was misleading.

The second model gave us a more realistic estimate of what we could achieve with the intended inputs.

And that is the point worth remembering:

A machine learning model isn’t trustworthy because its metrics look impressive. It’s trustworthy when those metrics come from a valid evaluation of the problem it is supposed to solve.

High accuracy might be the result of excellent modeling.

It might also be the result of a hidden shortcut.

Knowing the difference is one of the most important skills in machine learning.

Because sometimes, the first sign that something is wrong with your model isn’t a terrible score.

It’s a score that looks almost too good to be true.

I write about machine learning, AI engineering, Python, and the challenges of building reliable intelligent systems.

More of my work: khawajalaeeq.me

--

--

Khawaja Muhammad Laeeq
Khawaja Muhammad Laeeq