Universidad Católica del Uruguay

Práctica 11

Práctica 11: Temporal Feature Engineering

  • Autores: Joaquín Batista, Milagros Cancela, Valentín Rodríguez, Alexia Aurrecoechea, Nahuel López (G1)
  • Unidad temática: UT3 · Feature Engineering
  • Tipo: Práctica guiada – Assignment UT3-11
  • Entorno: Python · Pandas · Scikit-learn · Matplotlib · Seaborn · NumPy
  • Dataset: Online Retail (Kaggle) · 397 884 transacciones · 4 338 usuarios · 18 562 órdenes
  • Fecha: Octubre 2025
  • Notebook: Práctica 11 - Temporal Feature Engineering
  • Tiempo estimado: 120–150 minutos

🎯 Objetivos de Aprendizaje

  • Implementar lag features usando groupby().shift() para capturar valores históricos sin leakage.
  • Aplicar rolling y expanding windows para modelar tendencias a corto y largo plazo.
  • Calcular métricas RFM para entender el comportamiento de recompra.
  • Construir agregaciones por ventanas temporales (7d, 30d, 90d) que midan actividad reciente.
  • Codificar variables calendáricas con encoding cíclico (sin/cos).
  • Evaluar modelos con validación temporal (TimeSeriesSplit) previniendo leakage.
  • Comparar desempeño con y sin temporal features.

📊 Dataset y Contexto de Negocio

Online Retail Dataset

  • Target: will_purchase_again (1 si el cliente compra nuevamente).
  • Distribución: 85.8 % sí · 14.2 % no.
  • Período: 2010-12-01 a 2011-12-09 (373 días).
  • Promedio de órdenes: 4.27 por usuario (5.99 para recurrentes).

Escenario: una empresa de e-commerce necesita anticipar si un cliente realizará otra compra. El reto es capturar patrones temporales fieles a la causalidad y evitar usar información futura.

Exploración temporal de órdenes y distribuciones


🔬 Metodologías Implementadas

1. Preparación y agregación a nivel orden

df = (
    df_raw.dropna(subset=["CustomerID"])
          .loc[~df_raw["InvoiceNo"].astype(str).str.startswith("C")]
)
df = df[(df["Quantity"] > 0) & (df["UnitPrice"] > 0)]
df["total_amount"] = df["Quantity"] * df["UnitPrice"]
df = df.sort_values(["user_id", "order_date"]).reset_index(drop=True)
  • Se consolidaron transacciones al nivel order_id, generando cart_size y order_total.
  • Se añadieron columnas básicas: order_number, days_since_prior_order.

2. Lag features

orders_df["days_since_prior_lag_1"] = (
    orders_df.groupby("user_id")["days_since_prior_order"].shift(1)
)
  • groupby().shift() garantiza historial por usuario y elimina leakage.
  • Se generaron lags de 1, 2 y 3 órdenes previas.

3. Rolling y expanding windows

orders_df["rolling_cart_mean_3"] = (
    orders_df.groupby("user_id")["cart_size"]
    .shift(1)  # excluye orden actual
    .rolling(window=3, min_periods=1)
    .mean()
    .reset_index(level=0, drop=True)
)
  • Rolling (3 órdenes) captura tendencias recientes.
  • Expanding acumula desde la primera compra para entender el histórico.

Comparación rolling vs expanding

4. RFM (Recency, Frequency, Monetary)

  • recency_days, frequency_total_orders, monetary_avg y monetary_total.
  • monetary_avg se calculó con acumulados expandibles para evitar divisiones por cero.

Distribución de métricas RFM

5. Ventanas temporales (7d, 30d, 90d)

  • Conteo y gasto en distintos horizontes (orders_7d, spend_30d, orders_90d, etc.).
  • Permiten detectar activación o dormancia de clientes.

Comparación de ventanas temporales

6. Product diversity

  • unique_products, product_diversity_ratio y métricas derivadas.
  • Capturan si el cliente explora o repite productos.

Diversidad de productos

7. Calendar features y encoding cíclico

orders_df["hour_sin"] = np.sin(2 * np.pi * orders_df["order_hour_of_day"] / 24)
orders_df["hour_cos"] = np.cos(2 * np.pi * orders_df["order_hour_of_day"] / 24)
  • Variables binarias (is_weekend, is_month_start, is_holiday) y codificación sin/cos para hora, día y mes.

Calendar encoding cíclico

8. Variables externas (indicadores económicos)

  • gdp_growth, unemployment_rate, consumer_confidence agregadas por mes.
  • Solo ffill para mantener causalidad.

Indicadores económicos y correlación

9. Validación temporal y evaluación de modelos

  • Se utilizó TimeSeriesSplit(n_splits=3) verificando que train_max < val_min.
  • Comparación:
    • Modelo base (sin temporal): AUC 0.6625 ± 0.0254.
    • Modelo con temporal: AUC 0.7204 ± 0.0623.
  • Mejora absoluta: +0.0580 AUC (8.7 %).

Comparación de performance

10. Feature importance

  • Feature importance de un Gradient Boosting demostró que:
    • product_diversity_ratio, recency_days, unique_products, spend_90d, days_since_prior_lag_3 son top 5.
    • Lag/Window features suman 28.8 % de importancia total.

Importancia de features temporales


🛡️ Data Leakage Detection

Checklist aplicado:

  • groupby().shift(1) en todas las agregaciones temporales.
  • Sin bfill, solo ffill.
  • TimeSeriesSplit garantizando orden cronológico.
  • Verificación de brecha razonable entre train y CV.
  • Revisión manual de top features para descartar columnas filtradas.

Resultado: no se detectó leakage en el pipeline.


🎓 Conclusiones e Insights

  • Temporal features aportaron +8.7 % de mejora en AUC.
  • Categorías más influyentes:
    • Lag/Window (28.8 %)
    • Diversity (17.1 %)
    • RFM (15.0 %)
  • Los features de ventanas temporales permiten identificar cambios recientes.
  • La diversidad de productos es un predictor clave de recompra.

Reglas de oro anti-leakage

  • df.groupby("user")["feature"].shift(1) antes de cualquier rolling/expanding.
  • No usar shift global sin agrupar.
  • Validar siempre con splits temporales.
  • Documentar los pasos y versionar el pipeline.

🔍 Preguntas de Reflexión

  1. Ventanas temporales más relevantes: 30 días ofreció mejor balance señal/ruido frente a 7 (ruidoso) y 90 (diluido).
  2. Variables económicas: aportaron poco al ser simuladas y de baja resolución temporal; su valor crecería con datos reales y más frecuentes.
  3. RFM más predictivo: recency_days, seguido de frequency_total_orders; monetary aporta pero con menor peso.
  4. Señales de leakage: ninguna; el monitoreo de gaps, feature importance y revisiones manuales confirmó integridad.
  5. Deploy diario: mantener feature store incremental, cálculos online de lags/ventanas, versionado de features/modelos, monitoreo continuo y estrategias para cold-start.

📚 Referencias y Recursos

  • Kaggle – Online Retail Dataset.
  • Feature Engineering for Machine Learning – capítulo de temporal features.
  • Documentación de Pandas (operaciones temporales).
  • Scikit-learn – TimeSeriesSplit.
  • Framework RFM para e-commerce.