Si te gusta Skforecast , ayúdanos dándonos una estrella en GitHub! ⭐️
Más sobre forecasting en: cienciadedatos.net
El data leakage, también conocido como information leakage, ocurre cuando datos externos al conjunto de entrenamiento influyen inadvertidamente en el modelo durante el proceso de entrenamiento. Este problema genera estimaciones de rendimiento demasiado optimistas durante la evaluación del modelo y dificulta su capacidad de generalización a nuevos datos. En la predicción de series temporales, el data leakage suele ocurrir cuando el modelo tiene acceso a valores futuros que no estarían disponibles en el momento de la predicción.
Este problema es especialmente crítico al trabajar con modelos preentrenados, como los modelos fundacionales para series temporales, ya que los usuarios generalmente no participan en el proceso de entrenamiento. Para mitigar el data leakage, la mayoría de los autores informan sobre las series utilizadas para preentrenar el modelo, lo que permite a los usuarios verificar que los datos empleados en la evaluación no hayan sido vistos durante el entrenamiento. Sin embargo, garantizar la separación de datos en la fase de preentrenamiento no es suficiente para evitar el data leakage. En la predicción de series temporales, también es crucial impedir que el modelo acceda a datos más recientes que el período designado para la validación. Esto se debe a que, si una serie utilizada en el entrenamiento está altamente correlacionada con la serie empleada en la evaluación, el modelo podría acceder de manera indirecta a información que no debería utilizar.
El riesgo de este tipo data leakage es especialmente alto en modelos entrenados con miles de series temporales, ya que es probable que algunas de ellas presenten una fuerte correlación con la serie que el usuario desea predecir.
Para ilustrar este fenómeno, se lleva a cabo un experimento en el que se entrenan dos modelos con varias series temporales que presentan un alto grado de correlación. Luego, se evalúa un modelo con una serie que ha sido excluida del conjunto de entrenamiento, pero que corresponde a un período de tiempo ya observado durante el entrenamiento. Los resultados se comparan con aquellos obtenidos cuando el período de test se excluye por completo de los datos de entrenamiento. Si el modelo muestra un desempeño significativamente mejor en el primer escenario, esto indica que está aprovechando información a la que no debería tener acceso, lo que confirma la presencia data leakage.
Para evitar el data leakage y garantizar una evaluación justa, el modelo no debe tener acceso a ningún dato del período de test designado.
Las librerías utilizadas en este documento son:
# Tratamiento de datos
# ==============================================================================
import pandas as pd
from skforecast.datasets import fetch_dataset
# Gráficos
# ==============================================================================
import matplotlib.pyplot as plt
from skforecast.plot import set_dark_theme
# Modelado
# ==============================================================================
import skforecast
from sklearn.linear_model import Ridge
from sklearn.preprocessing import StandardScaler
from skforecast.recursive import ForecasterRecursiveMultiSeries
# Configuración
# ==============================================================================
import warnings
warnings.filterwarnings('once')
color = '\033[1m\033[38;5;208m'
print(f"{color}Versión skforecast: {skforecast.__version__}")
Los datos utilizados en este documento contienen el número diario de pasajeros de varios servicios de transporte público en Madrid.
# Descarga de datos
# ==============================================================================
data = pd.read_csv(
"https://raw.githubusercontent.com/skforecast/skforecast-datasets/refs/heads/"
"main/data/public-transport-madrid.csv"
)
data["date"] = pd.to_datetime(data["date"])
data = data.set_index("date")
data = data.asfreq("D")
data = data.drop(columns=["total"])
data.head()
# Gráfico de las series
# ==============================================================================
set_dark_theme()
fig, ax = plt.subplots(figsize=(7, 3.5))
data.plot(ax=ax, legend=True)
ax.set_title('Users of public transport in Madrid')
ax.set_xlabel('')
ax.legend(loc='upper left');
# Matriz de correlación entre series
# ==============================================================================
correlation = data.corr()
correlation
El gráfico y la matriz de correlación de las series muestran que estas están altamente correlacionadas.
# Variables exógenas basadas en calendario
# ==============================================================================
exog = pd.DataFrame(index=data.index)
exog['day'] = exog.index.day
exog['month'] = exog.index.month
exog['quarter'] = exog.index.quarter
exog['dayofweek'] = exog.index.dayofweek
exog['dayofyear'] = exog.index.dayofyear
exog['year'] = exog.index.year
exog.head(4)
Se entrenan dos modelos de predicción utilizando las series disponibles, excluyendo metro
. Luego, se evalúa el rendimiento de los modelos en la serie excluida metro
en dos escenarios diferentes:
# División datos: train-test
# ==============================================================================
end_train = '2024-07-31 23:59:00'
data_train = data.loc[:end_train, :].copy()
data_test = data.loc[end_train:, :].copy()
exog_train = exog.loc[:end_train, :].copy()
exog_test = exog.loc[end_train:, :].copy()
print(f"Train dates : {data_train.index.min()} --- {data_train.index.max()} (n={len(data_train)})")
print(f"Test dates : {data_test.index.min()} --- {data_test.index.max()} (n={len(data_test)})")
Modelo que no ha visto la serie objetivo ni ninguna otra serie en el período de test
# Entrenar forecaster
# ==============================================================================
lags = [1, 7, 14, 364]
forecaster_1 = ForecasterRecursiveMultiSeries(
regressor = Ridge(random_state=951),
lags = lags,
transformer_series = StandardScaler(),
encoding = None,
forecaster_id = 'forecaster_no_leakage'
)
forecaster_1.fit(series=data_train.drop(columns='metro'), exog=exog_train)
# Predicciones
# ==============================================================================
predictions_1 = forecaster_1.predict(
steps = len(data_test),
last_window = data_train[['metro']],
exog = exog_test,
levels = ["metro"]
)
predictions_1 = predictions_1.rename(columns={'metro': 'pred_model_1'})
predictions_1.head(3)
Modelo que no ha visto la serie objetivo, pero sí ha visto el período de prueba de las otras series
# Entrenar forecaster
# ==============================================================================
lags = [1, 7, 14, 364]
forecaster_2 = ForecasterRecursiveMultiSeries(
regressor = Ridge(random_state=951),
lags = lags,
transformer_series = StandardScaler(),
encoding = None,
forecaster_id = 'forecaster_with_leakage'
)
forecaster_2.fit(series=data.drop(columns='metro'), exog=exog)
# Predicciones
# ==============================================================================
predictions_2 = forecaster_2.predict(
steps = len(data_test),
last_window = data_train[['metro']],
exog = exog_test,
levels = ["metro"]
)
predictions_2 = predictions_2.rename(columns={'metro': 'pred_model_2'})
predictions_2.head(3)
# Resultados
# ==============================================================================
results = pd.concat([data_test['metro'], predictions_1, predictions_2], axis=1)
fig, ax = plt.subplots(figsize=(7, 3.5))
data_test['metro'].plot(ax=ax, label='True')
results['pred_model_1'].plot(ax=ax, label='No leakage')
results['pred_model_2'].plot(ax=ax, label='With leakage')
ax.set_title('Users of public transport in Madrid')
ax.set_xlabel('')
ax.legend()
plt.show();
# Prediction error for each model
# ==============================================================================
mae_1 = (results['metro'] - results['pred_model_1']).abs().mean()
mae_2 = (results['metro'] - results['pred_model_2']).abs().mean()
improvement = (mae_1 - mae_2) / mae_1
print(f"MAE model {forecaster_1.forecaster_id}: {mae_1}")
print(f"MAE model {forecaster_2.forecaster_id}: {mae_2}")
print(f"Improvement: {100 * improvement:.2f}%")
Aunque ninguno de los modelos ha visto directamente la serie objetivo, el segundo modelo ha estado expuesto al período de test de otras series. Dado que algunas de estas series están altamente correlacionadas con la serie objetivo, el modelo ha accedido indirectamente a información futura, lo que le permite hacer predicciones más precisas que el primer modelo.
Este ejemplo ilustra cómo puede producirse data leakage incluso cuando la serie objetivo no forma parte del conjunto de entrenamiento. Para evitar la filtración de información y garantizar una evaluación justa, el modelo no debe tener acceso a ningún dato del período de test designado.
import session_info
session_info.show(html=False)
¿Cómo citar este documento?
Si utilizas este documento o alguna parte de él, te agradecemos que lo cites. ¡Muchas gracias!
Data leakage en modelos de forecasting preentrenados por Joaquín Amat Rodrigo y Javier Escobar Ortiz, disponible bajo una licencia Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0 DEED) en https://cienciadedatos.net/documentos/py63-data-leakage-modelos-forecasting-preentrenados.html
¿Cómo citar skforecast?
Si utilizas skforecast, te agradeceríamos mucho que lo cites. ¡Muchas gracias!
Zenodo:
Amat Rodrigo, Joaquin, & Escobar Ortiz, Javier. (2024). skforecast (v0.14.0). Zenodo. https://doi.org/10.5281/zenodo.8382788
APA:
Amat Rodrigo, J., & Escobar Ortiz, J. (2024). skforecast (Version 0.14.0) [Computer software]. https://doi.org/10.5281/zenodo.8382788
BibTeX:
@software{skforecast, author = {Amat Rodrigo, Joaquin and Escobar Ortiz, Javier}, title = {skforecast}, version = {0.14.0}, month = {11}, year = {2024}, license = {BSD-3-Clause}, url = {https://skforecast.org/}, doi = {10.5281/zenodo.8382788} }
Este documento creado por Joaquín Amat Rodrigo y Javier Escobar Ortiz tiene licencia Attribution-NonCommercial-ShareAlike 4.0 International.
Se permite:
Compartir: copiar y redistribuir el material en cualquier medio o formato.
Adaptar: remezclar, transformar y crear a partir del material.
Bajo los siguientes términos:
Atribución: Debes otorgar el crédito adecuado, proporcionar un enlace a la licencia e indicar si se realizaron cambios. Puedes hacerlo de cualquier manera razonable, pero no de una forma que sugiera que el licenciante te respalda o respalda tu uso.
No-Comercial: No puedes utilizar el material para fines comerciales.
Compartir-Igual: Si remezclas, transformas o creas a partir del material, debes distribuir tus contribuciones bajo la misma licencia que el original.