Atlasingeniería

Aprendizaje automáticoFundamentosTema 3

Validación cruzada y separación de datos

Separar datos parece trivial y es donde se filtran los errores más caros: información del futuro, filas repetidas entre particiones y decisiones tomadas mirando el conjunto de prueba.

Para este tema conviene tener claro:Qué significa que un modelo aprenda

Un modelo con 99% de exactitud en validación y 60% en producción no suele ser un problema de modelado: es un problema de cómo se separaron los datos. La validación mide lo que se le permite medir, y si algo se filtró, mide una fantasía.

Entrenamiento, validación y prueba

Los datos se parten en tres. Entrenamiento, con el que el modelo ajusta sus parámetros. Validación, con el que se eligen los hiperparámetros y se compara entre modelos. Prueba, que se usa una sola vez, al final, para estimar el desempeño real.

Los tres son necesarios justamente porque elegir también es aprender. Si se usan los mismos datos para elegir el modelo y para estimar su error, esa estimación queda optimista: el proceso se ajustó a esos datos aunque cada modelo individual no lo haya hecho.

Antes de seguir, predecí

Normalizás todos los datos y después los partís en entrenamiento y validación. ¿Está bien?

Rotar la partición k veces

Con pocos datos, apartar un tercio duele y además la estimación depende mucho de qué filas cayeron en cada lado. La validación cruzada en kk partes resuelve las dos cosas: se divide en kk bloques, se entrena kk veces dejando uno afuera cada vez, y se promedian los resultados.

Todos los datos sirven para entrenar y para validar, en rondas distintas. El costo es entrenar kk veces, y valores de 5 o 10 son lo habitual. La variabilidad entre rondas también informa: si los resultados difieren mucho, la estimación es frágil.

Los datos se parten en cinco bloques del mismo tamaño.

1 / 5
Cada fila es una ronda. El bloque marcado con V es el que se aparta para validar; los demás entrenan. Al final, cada dato fue de validación exactamente una vez.

La fuga de datos y su forma clásica

El error grave se llama fuga de datos: información del conjunto de validación que se coló en el entrenamiento. La forma clásica es normalizar o imputar usando estadísticas calculadas sobre todo el conjunto antes de partirlo.

Parece inofensivo y no lo es: el promedio usado para escalar ya contiene información de los datos de validación. La regla es que toda transformación que aprenda algo de los datos debe ajustarse sólo con el entrenamiento y aplicarse después al resto. Por eso los pipelines existen: encapsulan esa disciplina para que no dependa de la memoria de quien programa.

Con series temporales, partir al azar está mal

Con series temporales, la partición al azar está mal por definición: entrenar con datos de marzo para predecir febrero es usar el futuro para predecir el pasado, y eso no va a existir en producción.

La partición tiene que ser temporal: entrenar con lo viejo, validar con lo nuevo, y repetir moviendo la ventana hacia adelante. Conviene además dejar un hueco entre entrenamiento y validación si hay efectos que se arrastran, para que no se filtren por continuidad.

Cuando las filas no son independientes

El otro caso frecuente es cuando las filas no son independientes. Varias consultas del mismo paciente, varias fotos del mismo producto, varias transacciones del mismo cliente.

Si el mismo grupo cae en entrenamiento y en validación, el modelo puede reconocer al grupo en vez de aprender el patrón, y la métrica sale inflada. La partición tiene que ser por grupo: todas las filas de un cliente van juntas a un solo lado.

Estratificar con clases desbalanceadas

Con clases desbalanceadas conviene estratificar: que cada partición conserve la proporción original de clases. Sin eso, con un 2% de positivos, una partición puede quedarse casi sin ninguno y la métrica se vuelve ruido.

Y una advertencia sobre el conjunto de prueba: cada vez que se lo mira para decidir algo, deja de ser una estimación limpia. Si hubo que usarlo varias veces, lo honesto es decirlo, o conseguir datos nuevos para la evaluación final.

La validación que no filtra información

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import cross_val_score, StratifiedKFold, TimeSeriesSplit

# Todo el preprocesamiento adentro del pipeline: se ajusta con cada partición de entrenamiento
modelo = Pipeline([
    ("escalar", StandardScaler()),
    ("clasificador", LogisticRegression()),
])

# Estratificado: cada ronda conserva la proporción de clases
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=0)
scores = cross_val_score(modelo, X, y, cv=cv, scoring="average_precision")

print(scores.mean(), scores.std())   # el desvío importa tanto como el promedio

# Con series de tiempo, las particiones no pueden ser al azar
cv_tiempo = TimeSeriesSplit(n_splits=5)   # cada ronda entrena con el pasado y valida con el futuro

Poner el escalador adentro del pipeline no es prolijidad: es lo que impide la fuga. Si se escala antes de la validación cruzada, cada ronda de entrenamiento ya vio las estadísticas de su propio conjunto de validación, y el resultado sale optimista.

El desvío estándar de los cinco puntajes se reporta junto con el promedio por un motivo concreto: si las rondas difieren mucho, la estimación es frágil y la diferencia entre dos modelos puede ser ruido.

Qué esquema corresponde

SituaciónEsquemaPor qué
Datos independientes y balanceadosk-fold, k = 5 o 10el default razonable
Clases desbalanceadasestratificadosi no, alguna ronda puede no tener positivos
Filas agrupadas por entidadagrupado por esa entidadevita memorizar el grupo
Series de tiempoparticiones temporalesentrenar con el futuro es fuga
Muy pocos datosdejar uno afuerausa todo, y es caro
Muchos datosuna sola partición alcanzala validación cruzada es k veces más cara
Las dos filas del medio son las que más se equivocan en la práctica, y las dos producen el mismo síntoma: métricas excelentes en validación y un modelo que en producción no funciona.

Cierre

Entrenamiento para ajustar, validación para elegir, prueba una sola vez. La validación cruzada aprovecha datos escasos, y las trampas son siempre las mismas: transformaciones ajustadas antes de partir, particiones al azar en series temporales y filas del mismo grupo repartidas entre lados.

Autoevaluación

¿Lo entendiste?

¿Por qué hacen falta tres conjuntos y no dos?
¿Qué resuelve la validación cruzada en k partes?
Los resultados difieren mucho entre rondas. ¿Qué dice eso?
99% en validación y 60% en producción. ¿Qué hay que revisar primero?