Data Leakage: el enemigo silencioso que destruye tus modelos de Machine Learning


Data Leakage: El Enemigo Silencioso que Destruye tus Modelos de Machine Learning

Hoy entramos en uno de los problemas más peligrosos y menos visibles del ML real: el data leakage.

Un modelo de predicción de fraude con 99.8% de precisión en validación. El equipo celebra. Se despliega a producción. Resultado: 52% de precisión.

¿Qué pasó?

Una columna llamadatransaction_reversedque solo existía después de detectar el fraude. Data leakage en estado puro.

Si alguna vez has entrenado un modelo que parecía perfecto en validación pero se derrumbó en producción, es muy probable que el culpable fuera este fenómeno.

El data leakage no lanza warnings. No rompe el código. No genera excepciones.

Pero destruye la capacidad de generalización de un modelo. Y lo peor: puede pasar desapercibido incluso para equipos experimentados.

¿Qué es exactamente el data leakage?

El data leakage ocurre cuando información del futuro o del conjunto de validación se filtra en el entrenamiento del modelo.

Es decir, el modelo aprende patrones que no existirán en un escenario real.

Por eso, durante la validación:

  • La precisión parece altísima
  • El AUC se dispara
  • La pérdida cae en picado

Pero en producción:

  • El rendimiento se desploma
  • Las predicciones se vuelven inconsistentes
  • El modelo deja de ser útil

En otras palabras: el modelo hace «trampa» sin que nos demos cuenta.

Infografía explicando qué es el data leakage y cómo evitarlo en modelos de Machine Learning

Los 4 tipos de data leakage más comunes

1. Leakage por filtración temporal

El más peligroso y el más frecuente.

Ocurre cuando el modelo usa información del futuro para predecir el pasado.

Ejemplo concreto:

Imagina predecir si un cliente comprará en marzo usando como featuregasto_promedio_trimestre_1. Si ese trimestre incluye marzo, estás usando el futuro para predecir el presente.

El modelo aprende que «gasto alto en Q1 = compra en marzo» porque marzo está dentro de Q1. En producción, cuando predices en marzo, no tienes el gasto completo del trimestre.

Otro caso típico:

python
# ❌ Incorrecto
df['avg_purchase_next_30_days'] = df.groupby('user_id')['amount'].rolling(30).mean()

# ✅ Correcto
df['avg_purchase_last_30_days'] = df.groupby('user_id')['amount'].shift(1).rolling(30).mean()

2. Leakage por preprocesamiento incorrecto

Sucede cuando aplicamos transformaciones antes de dividir los datos.

Operaciones peligrosas:

  • Normalización
  • Estandarización
  • Imputación de valores faltantes
  • Selección de características
  • Encoding de variables categóricas

Si estas operaciones se hacen sobre todo el dataset, el modelo «ve» información del conjunto de validación.

❌ Incorrecto:

python
# Normalizar TODO el dataset primero
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_train, X_test = train_test_split(X_scaled)

✅ Correcto:

python
# Dividir primero, transformar después
X_train, X_test = train_test_split(X)
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)  # fit_transform en train
X_test_scaled = scaler.transform(X_test)        # solo transform en test

La diferencia: en el enfoque correcto, el scaler solo «aprende» de los datos de entrenamiento.

3. Leakage por variables altamente correlacionadas

Variables que contienen indirectamente la respuesta.

Red flags de variables sospechosas:

  • Nombres que incluyen «final», «resultado», «status_actual», «cancelado»
  • Correlación > 0.95 con el target
  • Valores que solo existen después del evento objetivo
  • Columnas que un humano no tendría disponibles al momento de predecir

Ejemplo real:

Predecir churn usando una columnafecha_de_cancelacion. Si esa columna tiene valor, el cliente ya hizo churn. Es como predecir si va a llover mirando si el suelo está mojado.

4. Leakage por duplicados o registros relacionados

Muy común en:

  • Datos médicos (mismo paciente, múltiples visitas)
  • Transacciones (mismo usuario, múltiples compras)
  • Series temporales
  • Datasets con múltiples filas por entidad

Si un mismo usuario aparece en train y test, el modelo memoriza patrones específicos de ese usuario en lugar de aprender patrones generales.

Solución:

python
# Dividir por entidad, no por filas
from sklearn.model_selection import GroupShuffleSplit

splitter = GroupShuffleSplit(test_size=0.2, random_state=42)
train_idx, test_idx = next(splitter.split(X, y, groups=df['user_id']))

Cómo detectar data leakage

Señales de alarma

  1. Precisión sospechosamente alta (>95% en problemas complejos del mundo real)
  2. Una variable domina el modelo (feature importance >80%)
  3. Rendimiento se desploma en producción (>15% de caída)
  4. Validación cruzada da resultados muy inconsistentes
  5. El modelo funciona «demasiado bien» con muy pocos datos

Test rápido

Elimina las top 3 variables más importantes de tu modelo.

Si el rendimiento colapsa completamente (cae >50%), investiga esas variables a fondo. Es probable que contengan leakage.

Preguntas clave para cada feature

  • ¿Esta variable existiría en el momento de la predicción?
  • ¿Contiene información del futuro?
  • ¿Es un proxy directo de la etiqueta?
  • ¿Cómo se calculó? ¿Incluye datos posteriores al evento?

Cómo evitarlo: las reglas de oro

1. Divide primero, transforma después

El orden correcto:

  1. Train/Test split
  2. Preprocesamiento ajustado solo con train
  3. Aplicar transformaciones al test usando los parámetros del train

Usa pipelines para automatizarlo:

python
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.ensemble import RandomForestClassifier

# El pipeline garantiza el orden correcto
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('classifier', RandomForestClassifier())
])

# fit solo ve los datos de train
pipeline.fit(X_train, y_train)

# predict usa los parámetros aprendidos de train
y_pred = pipeline.predict(X_test)

2. Respeta la temporalidad

En series temporales:

❌ Nunca hagas esto:

python
from sklearn.model_selection import KFold

# KFold mezcla pasado y futuro
kfold = KFold(n_splits=5, shuffle=True)

✅ Haz esto:

python
from sklearn.model_selection import TimeSeriesSplit

# TimeSeriesSplit respeta el orden temporal
tscv = TimeSeriesSplit(n_splits=5)

Reglas para time series:

  • Nunca mezclar pasado y futuro
  • Usar splits cronológicos
  • Features con rolling windows: asegúrate de que no incluyen el punto a predecir
  • Siempre ordenar por tiempo antes de dividir

3. Revisa las variables con sentido de negocio

No confíes ciegamente en la importancia de features. Pregúntate:

  • ¿Esta variable existiría en el momento de la predicción?
  • ¿Cómo se recolecta en la realidad?
  • ¿Hay un delay entre el evento y la disponibilidad del dato?

Ejemplo real de e-commerce:

Predecir si un usuario comprará mañana usandoitems_in_cart_tomorrow. Obviamente, mañana no ha llegado aún.

4. Evita duplicados entre train y test

Especialmente crítico en:

  • Datos de usuarios (divide poruser_id)
  • Logs de aplicaciones (divide porsession_id)
  • Transacciones financieras (divide porcustomer_id)
  • Datos clínicos (divide porpatient_id)

5. Valida con datos «fuera del tiempo»

Si tu modelo se desplegará en enero 2027, valídalo con datos de diciembre 2026 que no usaste en entrenamiento.

Simula el escenario real: entrena con pasado, predice el futuro.

Casos reales con soluciones

Caso 1: Predicción de churn

❌ Incorrecto:

python
df['dias_desde_ultima_actividad'] = (datetime.now() - df['last_activity']).days

✅ Correcto:

python
# Usar una fecha de corte fija (la fecha en que harías la predicción)
fecha_corte = '2026-01-01'
df['dias_desde_ultima_actividad'] = (fecha_corte - df['last_activity']).days

Caso 2: Imputación de valores faltantes

❌ Incorrecto:

python
# Imputar con la media global
df['age'].fillna(df['age'].mean(), inplace=True)
X_train, X_test = train_test_split(df)

✅ Correcto:

python
X_train, X_test = train_test_split(df)

# Calcular la media solo del train
mean_age = X_train['age'].mean()

# Aplicar a ambos conjuntos
X_train['age'].fillna(mean_age, inplace=True)
X_test['age'].fillna(mean_age, inplace=True)

Caso 3: Normalización con StandardScaler

❌ Incorrecto:

python
scaler = StandardScaler()
df[['feature1', 'feature2']] = scaler.fit_transform(df[['feature1', 'feature2']])
X_train, X_test = train_test_split(df)

✅ Correcto:

python
X_train, X_test = train_test_split(df)

scaler = StandardScaler()
X_train[['feature1', 'feature2']] = scaler.fit_transform(X_train[['feature1', 'feature2']])
X_test[['feature1', 'feature2']] = scaler.transform(X_test[['feature1', 'feature2']])

Caso 4: Feature engineering con agregaciones

❌ Incorrecto:

python
# Agregar todas las transacciones del usuario (incluyendo futuras)
df['user_total_spent'] = df.groupby('user_id')['amount'].transform('sum')

✅ Correcto:

python
# Solo agregar transacciones anteriores a la fecha de corte
df = df.sort_values('transaction_date')
df['user_total_spent'] = df.groupby('user_id')['amount'].cumsum().shift(1)

Checklist antes de entrenar tu modelo

Usa esta lista de verificación antes de cada entrenamiento:

  • ¿Dividí los datos ANTES de cualquier transformación?
  • ¿Todas mis features existirían en el momento de predicción?
  • ¿Usé.fit_transform()solo en train y.transform()en test?
  • ¿Verifiqué que no hay duplicados o entidades compartidas entre train/test?
  • ¿Las métricas son «demasiado buenas para ser verdad»?
  • ¿Revisé las top 5 features más importantes con sentido de negocio?
  • ¿UséTimeSeriesSplitsi trabajo con series temporales?
  • ¿Implementé todo en un Pipeline para evitar errores manuales?
  • ¿Validé con datos completamente fuera del período de entrenamiento?

Herramientas que ayudan a prevenir leakage

Pipelines y automatización:

  • sklearn.pipeline.Pipeline– garantiza el orden correcto de operaciones
  • feature-engine– transformadores que respetan train/test split
  • category_encoders– encoding seguro de variables categóricas

Validación temporal:

  • sklearn.model_selection.TimeSeriesSplit– para series temporales
  • sklearn.model_selection.GroupShuffleSplit– para datos agrupados

Detección:

  • Analiza la distribución de features entre train/test
  • Compara feature importance con conocimiento del negocio
  • Monitorea el rendimiento en producción vs validación

Conclusión

El data leakage es uno de los errores más críticos en Machine Learning porque:

  1. No es evidente a simple vista
  2. Produce métricas engañosas
  3. Invalida completamente un modelo en producción
  4. Es extremadamente común, incluso en equipos experimentados

La buena noticia: se puede evitar siguiendo prácticas sólidas.

La regla de oro: Si tus métricas parecen demasiado buenas, probablemente lo sean. Investiga.

Un modelo sin leakage es un modelo que puede sobrevivir en producción. Y esa es la única métrica que realmente importa.


Recursos adicionales:


¿Has detectado data leakage en tus proyectos? ¿Qué otros tipos has encontrado? Comparte tu experiencia en los comentarios.

 

“Un modelo que generaliza es un modelo que vive.
Y el data leakage es su enemigo más silencioso.”