14 · Validación consciente del tiempo
Nunca barajes, nunca dividas al azar: valida los pronósticos walk-forward para que la ventana de entrenamiento siempre preceda a la de prueba. TimeSeriesSplit de scikit-learn lo hace por ti.
TimeSeriesSplit produce folds de ventana expansiva donde cada índice de entrenamiento precede a cada índice de prueba — CV walk-forward que imita el despliegue real (entrenar en el pasado, predecir el futuro). El KFold estándar mezcla el futuro en el train y reporta puntajes de fantasía.
Sin esto:
El k-fold aleatorio pone filas futuras en el train, filtrando información que ningún modelo en vivo podría tener; tu precisión reportada no significa nada y el modelo falla en cuanto enfrenta un futuro genuino.
Incluso con features perfectas, todavía puedes arruinar un modelo de series temporales en el paso de validación. La regla cardinal del Capítulo 1 vuelve con toda su fuerza: el futuro nunca debe aparecer en el entrenamiento.
La validación cruzada KFold estándar baraja todas las filas y las divide en folds. En data i.i.d. eso es ideal. En una serie temporal es fuga catastrófica: un fold aleatorio pone, digamos, junio y agosto en el train y le pide al modelo "predecir" julio — usando información de después de julio. El modelo esencialmente interpola entre fechas que ya vio. Tu puntaje de CV se dispara; producción colapsa, porque en realidad nunca tienes el futuro.
El esquema correcto es la validación walk-forward (también llamada CV de ventana expansiva u origen móvil). Entrenas sobre un trozo de la data más temprana, pruebas en el bloque inmediatamente siguiente, luego deslizas hacia adelante: creces (o ruedas) la ventana de entrenamiento y pruebas de nuevo en el siguiente bloque. Cada conjunto de prueba es estrictamente posterior a su conjunto de entrenamiento — exactamente lo que pasa en el despliegue.
scikit-learn empaqueta esto como TimeSeriesSplit(n_splits=k). Produce k folds donde los índices de entrenamiento siempre vienen antes de los de prueba, y (por defecto) la ventana de train se expande en cada fold. Abajo lo corremos sobre una serie indexada de juguete e imprimimos los rangos de índices de cada fold para que veas la ventana de train expansiva siempre sentada antes de la de prueba — y lo contrastamos con cómo KFold dispersaría el futuro al entrenamiento.
Python (in browser)
TimeSeriesSplit garantiza que el train termina antes de que empiece el test (walk-forward); KFold con shuffle dispersa el futuro al train — fuga.
Python runs entirely in your browser via Pyodide (~6 MB on first Run, cached after).
¿Por qué la validación cruzada KFold(shuffle=True) es inválida para una serie temporal, mientras TimeSeriesSplit es correcta?
- Nunca barajes ni dividas al azar una serie temporal; valida walk-forward para que el train siempre preceda al test.
- TimeSeriesSplit produce folds de ventana expansiva con max(idx train) < min(idx test); max_train_size lo convierte en ventana móvil.
- KFold(shuffle=True) dispersa filas futuras al train — fuga catastrófica que infla puntajes offline y falla en vivo.
El CV walk-forward es el estándar de oro para tunear y reportar cualquier modelo de pronóstico — ARIMA, gradient boosting o LSTM — y es cómo los leaderboards de series temporales de Kaggle evitan puntajes inflados por fuga.
Si lo quitas: Valida un forecaster con CV barajado y cada número que reportas es una ilusión inflada por fuga; el modelo que lució mejor offline puede ser el peor en producción.