cd /news/machine-learning/a-two-stage-workflow-to-detect-data-… · home topics machine-learning article
[ARTICLE · art-64110] src=dev.to ↗ pub= topic=machine-learning verified=true sentiment=· neutral

A Two-Stage Workflow to Detect Data Leakage.

A developer created a two-stage workflow to detect data leakage in machine learning models. The first stage uses fast correlation and single-feature R² to identify linear leaks, while the second stage trains a shallow decision tree to catch non-linear leaks via feature importance. The workflow flags features that explain more than 10% of the variance or dominate tree splits.

read4 min views1 publishedJul 17, 2026

Data leakage is the silent killer of machine learning models. You finish training, see an incredible 98% accuracy on your test set, and feel like a genius, until the model hits production and completely fails.

The most overlooked part of machine learning is the active prevention of data leakage. While robust cross-validation is a great way to verify if your model generalizes, it merely tells you that a problem exists. It doesn’t tell you where the leak is coming from.

To solve this, I’ve created a standardized, two-stage workflow designed to identify the exact columns causing data leakage directly and immediately. Before you spend hours tuning hyperparameters, run your data through these two lightning-fast checks.

Our first line of defense looks for direct, linear relationships. If a single column can perfectly (or almost perfectly) predict your target variable on its own, you likely have a leak—like an accidental "future" timestamp or an ID column that encodes the target label.

print("=== 1. Linear Leakage Check (Correlation & R²) ===")

correlations = x_train.corrwith(pd.Series(np.ravel(y_train), index=x_train.index), numeric_only=True).abs()
r2_approximations = correlations ** 2

leakage_df = pd.DataFrame({
    'Correlation (|r|)': correlations,
    'Single-Feature R²': r2_approximations
}).sort_values('Single-Feature R²', ascending=False)

high_leakage = leakage_df[leakage_df['Single-Feature R²'] > 0.10]

if len(high_leakage) > 0:
    print(f"🔴 Found {len(high_leakage)} potential leakage sources (R² > 10%):")
    print(high_leakage.head(20))
else:
    print("✅ No linearly leaky features found.")

(.abs())

because a strong negative correlation is just as predictive as a strong positive one.This step is computationally cheap. By relying on pandas' corrwith

method, the operations are heavily vectorized in C, meaning it can scan thousands of columns in a fraction of a second. It immediately highlights glaring linear leaks without requiring you to train a single model.

Linear correlation is great, but it misses complex, non-linear relationships. For example, a categorical ID mapped to integers might have a low linear correlation but still perfectly separate the target classes. To catch these, we move to Stage 2.

print("\n=== 2. Non-Linear Leakage Check (Tree Impurity) ===")

from sklearn.tree import DecisionTreeRegressor
import pandas as pd

dt = DecisionTreeRegressor(max_depth=5, random_state=42)
dt.fit(x_train, y_train)

tree_importance = pd.DataFrame({
    'Feature': x_train.columns,
    'Importance': dt.feature_importances_
}).sort_values('Importance', ascending=False)

top_tree_features = tree_importance[tree_importance['Importance'] > 0.10]

if len(top_tree_features) > 0:
    print(f"🔴 Found {len(top_tree_features)} suspicious features dominating tree splits:")
    print(top_tree_features.to_string(index=False))
else:
    print("✅ No single feature dominates the tree decisions.")

Train a Shallow Tree: We initialize a single DecisionTreeRegressor

with a shallow depth (max_depth=5)

. A decision tree works by continuously splitting the data into groups based on the feature that best separates the target variable.

Extract Feature Importance: Once the tree is fitted, we pull the feature_importances_

attribute. Scikit-learn calculates this based on impurity reduction—essentially tracking how much a specific feature helped the tree make clean splits.

Filter and Flag: We map these importances

back to the column names, sort them, and flag any feature that dictates more than 10% of the tree's overall decision-making process.

A single decision tree restricted to a depth of 5 is incredibly fast to train. If a specific feature is a massive source of non-linear data leakage, the tree is going to be instantly drawn to it, splitting on that feature at the very top (root) nodes. Furthermore, extracting the built-in impurity importance requires zero extra computation time once the model is fitted.

=== 1. Linear Leakage Check (Correlation & R²) ===
🔴 Found 6 potential leakage sources (R² > 10%):
                                                 Correlation (|r|)  \
target_encoder__apr_drg_code                              0.586974   
remainder__total_charges                                  0.578617   
target_encoder__ccs_diagnosis_code                        0.488559   
target_encoder__ccs_procedure_code                        0.480237   
target_encoder__apr_mdc_code                              0.376924   
one_hot_encoder__apr_severity_of_illness_code_4           0.347295   

                                                 Single-Feature R²  
target_encoder__apr_drg_code                              0.344538  
remainder__total_charges                                  0.334797  
target_encoder__ccs_diagnosis_code                        0.238690  
target_encoder__ccs_procedure_code                        0.230628  
target_encoder__apr_mdc_code                              0.142072  
one_hot_encoder__apr_severity_of_illness_code_4           0.120614  

=== 2. Non-Linear Leakage Check (Tree Impurity) ===

🔴 Found 2 suspicious features dominating tree splits:
                     Feature  Importance
    remainder__total_charges    0.752467
target_encoder__apr_drg_code    0.109771

By combining these two steps, you create an end-to-end, standardized workflow that catches both linear and non-linear data leakage before you commit to heavy model training. Embed this snippet at the top of your ML pipelines, and you'll never be caught off-guard by a leaky dataset in production again.

── more in #machine-learning 4 stories · sorted by recency
── more on @scikit-learn 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/a-two-stage-workflow…] indexed:0 read:4min 2026-07-17 ·