Un programa normal, si no se toca, sigue haciendo lo mismo indefinidamente. Un modelo no. Un modelo puede empeorar sin que nadie modifique una sola línea de código, porque lo que cambia es el mundo del que salieron sus datos.
Esta es la diferencia de fondo entre desplegar software y desplegar un modelo, y la razón de que exista una disciplina específica alrededor de ello.
Conviene distinguirlas porque tienen causas y remedios distintos.
Deriva de datos (data drift): cambia la distribución de lo que entra. El modelo sigue siendo tan válido como antes, pero recibe casos que no se parecen a los que vio entrenando y sobre los que, por tanto, extrapola. Si un modelo se entrenó con pasajeros de entre 20 y 40 años y de pronto empiezan a llegar octogenarios, el modelo no está roto: está opinando sobre territorio desconocido.
Deriva de concepto (concept drift): cambia la relación entre las entradas y lo que queremos predecir. Las entradas pueden parecer las mismas, pero lo que significan ya no. Un modelo de detección de fraude entrenado antes de que apareciera un tipo nuevo de estafa sufre esto: las transacciones se ven igual, pero la etiqueta correcta ha cambiado.
La primera se detecta mirando solo las entradas, que es información que siempre tenemos. La segunda exige conocer el resultado real, que casi siempre llega tarde y a veces no llega nunca.
ImportanteEl problema de las etiquetas tardías
Para saber si un modelo de riesgo crediticio acierta hay que esperar a que el préstamo se pague o no, lo que puede llevar años. Durante todo ese tiempo el modelo está decidiendo y nadie puede calcular su acierto real.
Por eso la monitorización no puede depender solo de las métricas de calidad. Hay que vigilar lo que sí se observa de inmediato: qué entra y qué sale.
13.2 Detectar deriva en las entradas
La pregunta es si dos muestras proceden de la misma distribución. Para una variable continua, el test de Kolmogorov-Smirnov compara las distribuciones acumuladas de ambas y nos da un p-valor.
Tomamos como referencia las edades del entrenamiento y simulamos dos lotes de producción: uno que se comporta con normalidad y otro en el que la población ha envejecido doce años.
edad_referencia =collect(skipmissing(Xtrain.Age))lote_normal =collect(skipmissing(Xtest.Age))lote_derivado = lote_normal .+12.0test_normal =ApproximateTwoSampleKSTest(edad_referencia, lote_normal)test_derivado =ApproximateTwoSampleKSTest(edad_referencia, lote_derivado)println("Lote normal p = ", round(pvalue(test_normal), digits =4))println("Lote derivado p = ", round(pvalue(test_derivado), digits =8))
Lote normal p = 0.7485
Lote derivado p = 0.0
El primer p-valor es alto, así que no hay evidencia de que el lote normal venga de una distribución distinta a la de entrenamiento, que es justo lo que esperábamos. El segundo es prácticamente cero: el test detecta la deriva sin ninguna duda.
AdvertenciaCuidado con el tamaño de la muestra
Un p-valor pequeño dice que la diferencia es detectable, no que sea importante. Con lotes de millones de registros, cualquier diferencia irrelevante da un p-valor minúsculo y el sistema de alertas se vuelve inútil a base de avisar de todo.
Por eso en producción suele vigilarse también el tamaño del efecto, por ejemplo el propio estadístico del test, y se fija un umbral sobre él y no solo sobre el p-valor.
Estadístico lote normal : 0.0548
Estadístico lote derivado : 0.3819
Para variables categóricas el planteamiento es el mismo pero comparando frecuencias. Basta con vigilar cuánto se mueve la proporción de cada categoría:
functionproporciones(v) total =length(v)Dict(nivel =>count(==(nivel), v) / total for nivel inlevels(v))endref =proporciones(Xtrain.Sex)lote =proporciones(Xtest.Sex)for nivel inkeys(ref)println(rpad(nivel, 8), " referencia ", round(ref[nivel], digits =3)," lote ", round(lote[nivel], digits =3)," variación ", round(abs(ref[nivel] - lote[nivel]), digits =3))end
male referencia 0.642 lote 0.66 variación 0.018
female referencia 0.358 lote 0.34 variación 0.018
13.3 Vigilar también la salida
Las entradas pueden pasar todos los controles y aun así estar ocurriendo algo raro. La distribución de las probabilidades que el modelo emite es un indicador barato y sorprendentemente informativo, porque resume el efecto conjunto de todas las variables.
probs_referencia = [pdf(p, 1) for p inpredict(mach, Xtrain)]probs_lote = [pdf(p, 1) for p inpredict(mach, Xtest)]println("Media referencia : ", round(mean(probs_referencia), digits =4))println("Media lote : ", round(mean(probs_lote), digits =4))println("KS sobre salidas p = ", round(pvalue(ApproximateTwoSampleKSTest(probs_referencia, probs_lote)), digits =4))
Media referencia : 0.3836
Media lote : 0.3743
KS sobre salidas p = 0.8225
Si la media de las probabilidades predichas se desplaza de forma sostenida, algo ha cambiado aguas arriba aunque ninguna variable por separado haya disparado una alerta.
13.4 Qué monitorizar en la práctica
Qué
Con qué frecuencia
Para detectar
Distribución de cada variable de entrada
Por lote o a diario
Deriva de datos
Proporción de valores ausentes por columna
Por lote
Roturas en el sistema que alimenta al modelo
Categorías no vistas en entrenamiento
Cada petición
Contratos de entrada rotos
Distribución de las predicciones
A diario
Cambios que no aparecen variable a variable
Métricas de calidad
Cuando lleguen las etiquetas
Deriva de concepto
Latencia y errores del servicio
Continuo
Problemas de ingeniería, no de modelo
Las tres primeras filas se suelen olvidar y son las que más pronto avisan. Un aumento repentino de valores ausentes en una columna casi nunca significa que el mundo haya cambiado: significa que alguien ha modificado una tabla aguas arriba.
13.5 Cuándo reentrenar
Detectada la deriva, la respuesta habitual es reentrenar con datos recientes. Hay varias políticas y ninguna es universalmente correcta:
Por calendario: reentrenar cada mes o cada trimestre. Simple y predecible, pero reentrena aunque no haga falta y llega tarde si la deriva es brusca.
Por umbral: reentrenar cuando una métrica de deriva supere un límite. Más eficiente, pero exige haber calibrado ese umbral y puede oscilar.
Por degradación medida: reentrenar cuando el acierto real caiga. Es el criterio más honesto y solo sirve si las etiquetas llegan con rapidez suficiente.
En todos los casos, reentrenar significa recorrer otra vez la cadena completa que hemos construido en este libro: preparar, ajustar el pipeline, validar y comparar contra el modelo actual antes de sustituirlo. Ese “comparar antes de sustituir” es importante, porque un modelo reentrenado no siempre es mejor.
TipReentrenar no es lo mismo que reajustar
Reajustar es volver a ejecutar el mismo pipeline con datos nuevos. Reentrenar de verdad puede implicar revisar qué variables siguen teniendo sentido, si han aparecido otras nuevas y si el tipo de modelo elegido sigue siendo el adecuado.
Lo primero se automatiza. Lo segundo requiere criterio y es donde el trabajo de ciencia de datos sigue siendo trabajo de personas.
Con esto cerramos el bucle que aparece en el diagrama del ciclo de vida: producción no desemboca en nada, vuelve a preparación. En el capítulo final veremos qué hace falta para que ese bucle sea trazable y no una sucesión de modelos de los que nadie recuerda de dónde salieron.