Variables temporals com a predictors
Una regressió lineal amb només l’índex temporal com a predictor captura la tendència però ignora tot allò altre. La solució no és canviar de model: és construir millors variables. Aquest procés —convertir la sèrie en un dataset tabular— s’anomena feature engineering temporal i és la base de gairebé tots els models de ML aplicats a sèries temporals.
De sèrie a taula
Per usar sklearn necessites un DataFrame on cada fila és un instant de temps i cada columna és una feature. La clau és que totes les features han de ser conegudes en el moment de la predicció: mai pots usar informació futura.
import numpy as np
import pandas as pd
np.random.seed(42)
dates = pd.date_range(start='2020-01-01', periods=60, freq='ME')
t = np.arange(60)
vendes = 50 + 0.8 * t + 10 * np.sin(2 * np.pi * t / 12) + np.random.normal(0, 4, 60)
serie = pd.Series(vendes, index=dates, name='vendes')
df = pd.DataFrame({'vendes': serie})
Variables lag: el passat com a predictor
La feature més natural en una sèrie temporal és el valor de períodes anteriors. Si les vendes d’aquest mes depenen de les del mes passat, el lag 1 captura aquesta dependència.
# Lags: valor de períodes anteriors
df['lag_1'] = df['vendes'].shift(1) # Valor del mes anterior
df['lag_2'] = df['vendes'].shift(2) # Valor de fa 2 mesos
df['lag_12'] = df['vendes'].shift(12) # Valor del mateix mes fa 1 any
Compte amb el data leakage:
shift(1)és segur perquè usa el valor del mes anterior per predir l’actual. Usarshift(0)seria trampa: estaries predint amb el valor que vols predir.
Mitjanes mòbils: suavitzar el passat
Les mitjanes mòbils capturen tendències recents sense el soroll d’un sol valor:
# Mitjanes mòbils de finestres anteriors (sempre amb shift per evitar leakage)
df['mitj_mov_3'] = df['vendes'].shift(1).rolling(window=3).mean()
df['mitj_mov_6'] = df['vendes'].shift(1).rolling(window=6).mean()
df['std_mov_3'] = df['vendes'].shift(1).rolling(window=3).std()
El shift(1) abans del rolling és important: garanteix que la mitjana dels últims 3 mesos no inclou el mes actual.
L’índex temporal explícit
Per capturar la tendència global, l’índex numèric del temps és una feature vàlida i senzilla:
df['t'] = np.arange(len(df))
df['mes'] = df.index.month
df['trimestre'] = df.index.quarter
df['any'] = df.index.year
Dummies estacionals: capturar l’estacionalitat
Si la sèrie té estacionalitat, els mesos de l’any són features molt informatives:
# Dummies de mes (gener és la categoria de referència amb drop_first=True)
dummies_mes = pd.get_dummies(df['mes'], prefix='mes', drop_first=True)
df = pd.concat([df, dummies_mes], axis=1)
| Feature | Tipus | Captura |
|---|---|---|
lag_1, lag_2 | Numèrica | Dependència de curt termini |
lag_12 | Numèrica | Estacionalitat anual via el passat |
mitj_mov_3 | Numèrica | Tendència recent suavitzada |
t | Numèrica | Tendència global |
mes_2…mes_12 | Binària | Efecte estacional per mes |
Eliminar files amb NaN i ajustar el model
from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_absolute_error, mean_squared_error
feature_cols = ['t', 'lag_1', 'lag_2', 'lag_12', 'mitj_mov_3'] + [c for c in df.columns if c.startswith('mes_')]
df_model = df[feature_cols + ['vendes']].dropna()
X = df_model[feature_cols]
y = df_model['vendes']
train_size = len(df_model) - 12
X_train, X_test = X.iloc[:train_size], X.iloc[train_size:]
y_train, y_test = y.iloc[:train_size], y.iloc[train_size:]
model = LinearRegression()
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
mae = mean_absolute_error(y_test, y_pred)
rmse = mean_squared_error(y_test, y_pred) ** 0.5
print(f'MAE: {mae:.2f}')
print(f'RMSE: {rmse:.2f}')
Quines features afegir segons el tipus de sèrie
| Característica de la sèrie | Features recomanades |
|---|---|
| Tendència lineal forta | t, t² si és quadràtica |
| Estacionalitat anual | lag_12, dummies mes_* |
| Alta autocorrelació curt termini | lag_1, lag_2, mitj_mov_3 |
| Volatilitat variable | std_mov_3, std_mov_6 |
| Sense estacionalitat clara | Evitar dummies de mes |
Resum
El feature engineering temporal transforma el problema de predicció de sèries en un problema de regressió estàndard. Les peces clau són: lags per capturar dependència, mitjanes mòbils per suavitzar tendències recents i dummies estacionals per als patrons cíclics. Al pròxim subcapítol veuràs com encaixa tot això en un exemple complet pas a pas.