MLOps — Módulo 10: drift — por qué el modelo se pudre solo
Módulo 10 del Curso de MLOps, el corazón de la disciplina: data drift vs concept drift con ejemplos reales de banca y retail, cómo detectarlo comparando referencia contra producción con tests estadísticos (KS, PSI) y un reporte de drift con Evidently.
☰ Índice del contenido
En el módulo anterior montamos las tres capas de monitoreo y quedó una señal marcada como la clave de MLOps: el drift. Vigilábamos las distribuciones de entrada sin explicar todavía por qué cambian ni cómo medir ese cambio con rigor. Este módulo es esa explicación — y es el corazón del curso completo. Si entiendes drift, entiendes por qué MLOps existe como disciplina aparte: es la respuesta a la pregunta “¿por qué un modelo que nadie tocó se degrada solo?”.
La tesis del módulo
Un modelo aprende la forma del mundo en un momento dado. El mundo no se queda quieto — y el modelo sí. Cuando la realidad se aleja de los datos con que el modelo aprendió, sus predicciones envejecen aunque el código sea idéntico. A ese alejamiento se le llama drift, y viene en dos sabores que se arreglan distinto.
Los dos tipos de drift
Toda degradación de un modelo por cambios en el mundo cae en una de dos categorías. Distinguirlas importa porque se detectan distinto y se arreglan distinto.
Data drift (glosado: cambian las distribuciones de las entradas — las features que le llegan al modelo ya no se ven como las de entrenamiento, aunque la relación entre entrada y resultado siga igual). El modelo sigue “sabiendo” la regla correcta, pero le están llegando datos de un tipo que casi no vio al entrenar, donde es menos confiable.
Concept drift (glosado: cambia la relación entre las entradas y lo que se predice — las features pueden verse igual que siempre, pero lo que significan cambió). Aquí la regla misma que el modelo aprendió dejó de ser cierta. Es el drift más traicionero porque las entradas pueden lucir perfectamente normales.
La distinción en una frase: data drift es que cambió el X; concept drift es que cambió la función que va de X a y.
Ejemplos concretos
El drift suena abstracto hasta que lo ves en tu propio dominio. Dos casos de banca y retail, el mundo donde esto se paga:
Concept drift — la inflación cambia el fraude. Un modelo antifraude aprendió que una compra de $500.000 en electrónica a medianoche era sospechosa. Llega un período de inflación fuerte: ahora ese monto es una compra normal de clase media, y el patrón de fraude se movió a otros montos y horarios. Las features (monto, hora, categoría) se ven parecidas, pero lo que significa “fraude” cambió. La relación X → fraude se movió. Eso es concept drift.
Data drift — una campaña cambia el perfil de clientes. Un modelo de riesgo crediticio se entrenó con la base histórica de clientes. El banco lanza una campaña agresiva dirigida a jóvenes universitarios. De golpe, la mayoría de las solicitudes vienen de un segmento (edad baja, ingreso variable, sin historial) que casi no existía en el entrenamiento. La regla X → riesgo puede seguir siendo válida, pero la distribución de X se desplazó hacia una zona donde el modelo tiene poca experiencia. Eso es data drift.
Cómo detectarlo: referencia contra actual
La mecánica de detección es siempre la misma idea: tomas una distribución de referencia (cómo se veían los datos cuando el modelo estaba sano, típicamente el set de entrenamiento) y la comparas contra la distribución actual (lo que llega en producción). Si se parecen, no hay drift. Si divergen más allá de un umbral, hay drift.
densidad
│ referencia actual
│ (entrenamiento) (producción)
│ ╱╲ ╱╲
│ ╱ ╲ ╱ ╲
│ ╱ ╲ ╱ ╲
│ ╱ ╲ ╱ ╲
│ ╱ ╲ ╱ ╲
│ ─────╱──────────╲──────────╱──────────╲─────
│ bajo centro viejo centro nuevo
└───────────────────────────────────────────►
valor de la feature
la distribución se corrió a la derecha en el tiempo:
el modelo ve valores que casi no vio al entrenar
Para decidir “¿se parecen o divergen?” no basta el ojo: se usan tests estadísticos que ponen un número al cambio.
- Test KS (Kolmogorov–Smirnov): compara dos distribuciones continuas y devuelve una distancia y un p-valor. Sirve para features numéricas.
- PSI (glosado: Population Stability Index, “índice de estabilidad de la población” — mide cuánto se movió una distribución respecto a una referencia, bucketizando los valores y sumando las diferencias). Es el favorito en banca por lo interpretable de su regla de dedo.
La regla de dedo clásica del PSI, ampliamente usada en la industria financiera:
| Valor de PSI | Interpretación | Qué hacer |
|---|---|---|
| < 0,1 | Sin cambio significativo | Nada, la población es estable |
| 0,1 – 0,25 | Cambio moderado | Vigilar de cerca, investigar la causa |
| > 0,25 | Cambio fuerte | Alarma: revisar el modelo, probable reentrenamiento |
Data drift vs concept drift, lado a lado
| Data drift | Concept drift | |
|---|---|---|
| Qué cambia | La distribución de las entradas X | La relación X → y |
| Las features se ven | Distintas a las de entrenamiento | Pueden verse normales |
| Se detecta con | Tests sobre las entradas (KS, PSI) | Caída de desempeño vs ground truth |
| Necesita ground truth | No — alarma temprana | Sí — por eso se ve tarde |
| Ejemplo | Campaña trae clientes nuevos | La inflación mueve el patrón de fraude |
| Suele arreglarse con | Reentrenar con datos frescos | Reentrenar, y a veces rediseñar features |
La fila que más duele es “necesita ground truth”: el data drift lo ves en las entradas sin esperar la etiqueta real; el concept drift muchas veces solo se confirma cuando el desempeño ya cayó. Por eso el data drift es tu alarma temprana y el concept drift tu confirmación tardía — se complementan.
Un reporte de drift con Evidently
Retomamos Evidently del módulo anterior, ahora enfocado en drift. El DataDriftPreset corre los tests estadísticos por columna automáticamente y decide, columna por columna y para el dataset completo, si hay drift:
import pandas as pd
from evidently import Report
from evidently.presets import DataDriftPreset
# referencia = distribución sana (entrenamiento).
# actual = ventana reciente de producción, mismas columnas.
referencia = pd.read_parquet("features_entrenamiento.parquet")
actual = pd.read_parquet("features_produccion_ultima_semana.parquet")
# DataDriftPreset aplica un test estadístico por columna (elige el
# apropiado según el tipo de dato y el tamaño de la muestra) y agrega
# un veredicto de dataset. drift_share fija qué fracción de columnas
# con drift marca el dataset completo como "en drift" (default 0,5).
UMBRAL = 0.3
reporte = Report([
DataDriftPreset(drift_share=UMBRAL, num_method="psi"),
])
snapshot = reporte.run(current_data=actual, reference_data=referencia)
resultado = snapshot.dict()
# DriftedColumnsCount: cuántas columnas driftearon y qué fracción son.
drift = next(m for m in resultado["metrics"]
if m["metric_name"].startswith("DriftedColumnsCount"))
n_drift, share = drift["value"]["count"], drift["value"]["share"]
print(f"Columnas con drift: {n_drift} ({share:.0%})")
# En un pipeline esto NO imprime: alimenta la decisión de reentrenar.
if share >= UMBRAL:
disparar_alerta_de_drift() # y, más adelante, evaluar reentrenamiento
Evidently elige el test por tipo de columna si no se lo fijas; aquí forzamos PSI para las numéricas (num_method="psi") justamente porque en banca es la regla de dedo que un comité de riesgo entiende. Tú defines el umbral de dataset (drift_share) según cuánta sensibilidad quieres.
El aviso que evita alarmas inútiles
Drift no implica automáticamente caída de desempeño. Una feature puede driftear sin que al modelo le importe — quizás esa variable pesaba poco, o el cambio cayó en una zona donde el modelo igual acierta. Si reentrenas cada vez que una columna se mueve un poco, vas a reentrenar sin parar, gastando cómputo y arriesgando meter un modelo peor. Mide el impacto real en el desempeño antes de alarmarte.
La secuencia sana no es “hay drift → reentrenar”. Es “hay drift → ¿cayó el desempeño (o hay razón fuerte para creer que caerá)? → recién ahí reentrenar”. El drift es la señal de dónde mirar, no la orden de actuar. Esa diferencia — señal versus trigger — es justamente el puente al próximo módulo, donde el drift se convierte en uno de los disparadores del reentrenamiento.
Errores comunes
- Confundir data drift con concept drift. Se detectan y se arreglan distinto. El data drift se ve en las entradas; el concept drift casi siempre exige el ground truth para confirmarse.
- Reentrenar ante cualquier drift. Drift en una feature irrelevante no justifica un reentrenamiento. Mide el impacto en el desempeño primero.
- Elegir mal la referencia. Si tu distribución de referencia no representa el estado sano, cada test miente. Suele ser el entrenamiento o una ventana estable reciente.
- Ignorar el concept drift porque “las features se ven normales”. Es el drift más peligroso justamente porque las entradas lucen bien mientras la regla que aprendió el modelo dejó de ser cierta.
- Usar solo el promedio de una feature para detectar drift. La media puede quedar igual mientras la forma de la distribución cambia por completo. Por eso se usan tests de distribución (KS, PSI), no comparaciones de promedios.
La frase para llevarse
“El modelo no se pudre porque envejezca su código, sino porque envejece su mundo. El drift es la medida de cuánto se ha alejado la realidad de lo que el modelo aprendió — y detectarlo a tiempo es la diferencia entre corregir y lamentar.”
Qué viene
Módulo 11: reentrenamiento, donde se cierra el loop. Ya detectas el drift; ahora veremos qué hacer con esa señal. Los triggers que disparan un reentrenamiento (programado, por drift, por caída de desempeño), cómo automatizar el pipeline de retraining, cómo validar el modelo nuevo antes de confiarle nada y cómo desplegarlo con red — champion/challenger, shadow y rollback.
Material relacionado
Preguntas sobre este curso
Regístrate gratis para hacer preguntas y guardar tu progreso.
✉ Entérate de lo nuevo
Recibe un aviso cuando publique nuevos cursos, workshops o investigaciones. Sin spam.