IntermédiaireMachine Learning
22 min de lecture19 vues

Séries Temporelles et Prévision avec Python

Apprenez à modéliser et prévoir des séries temporelles avec ARIMA, Prophet et XGBoost. Maîtrisez la validation temporelle correcte et les métriques adaptées.

Ce qui rend les séries temporelles différentes

En ML classique, on suppose que les observations sont indépendantes. Dans une série temporelle, la valeur d'aujourd'hui dépend des valeurs passées. Mélanger les données ou ignorer l'ordre casse cette structure.

La stationnarité

Une série est stationnaire si sa moyenne et sa variance sont constantes dans le temps. La plupart des séries réelles ne le sont pas (tendance à la hausse, saisonnalité).

ARIMA exige une série stationnaire. Il faut différencier la série (retirer la tendance) avant de modéliser.

from statsmodels.tsa.stattools import adfuller

result = adfuller(serie)
print(f"p-value ADF : {result[1]:.4f}")
# p-value < 0.05 → série stationnaire

1. Décomposition : tendance + saisonnalité + résidu

from statsmodels.tsa.seasonal import seasonal_decompose
import pandas as pd, numpy as np

dates = pd.date_range("2022-01-01", periods=104, freq="W")
values = 50 + np.arange(104) * 0.3 + 10 * np.sin(np.arange(104) * 2 * np.pi / 52) + np.random.normal(0, 2, 104)
serie = pd.Series(values, index=dates)

decomposition = seasonal_decompose(serie, model="additive", period=52)
# decomposition.trend    → tendance lissée
# decomposition.seasonal → pattern saisonnier
# decomposition.resid    → résidu (bruit)

Additif (tendance + saisonnalité + résidu) : si l'amplitude saisonnière est constante. Multiplicatif : si elle croît avec la tendance.


2. ARIMA et SARIMA

ARIMA(p, d, q)

ComposanteRôle
AR(p)Dépendance aux p valeurs passées
I(d)Différenciations pour stationnariser
MA(q)Dépendance aux q erreurs passées
from statsmodels.tsa.arima.model import ARIMA

model = ARIMA(serie, order=(2, 1, 1))  # p=2, d=1, q=1
result = model.fit()
forecast = result.forecast(steps=12)

SARIMA ajoute des termes saisonniers : SARIMA(p,d,q)(P,D,Q,s). Pour données mensuelles avec saisonnalité annuelle : s=12.

Choisir p, d, q manuellement via ACF/PACF est fastidieux. En pratique, utilisez auto_arima (pmdarima) ou passez directement à Prophet.


3. Prophet (Meta) : le meilleur choix pour commencer

Prophet modélise explicitement tendance + saisonnalités + jours fériés. Il est robuste aux données manquantes et facile à interpréter.

Avantages :

  • Détecte automatiquement les changepoints (ruptures de tendance)
  • Gère les jours fériés personnalisés
  • Fournit des intervalles de confiance sans effort

4. Micro-exercice : prédire des ventes avec Prophet

from prophet import Prophet
import pandas as pd, numpy as np

# Données simulées : ventes quotidiennes
dates = pd.date_range("2024-01-01", periods=365, freq="D")
sales = (100
         + np.arange(365) * 0.2
         + 20 * np.sin(np.arange(365) * 2 * np.pi / 7)
         + np.random.normal(0, 5, 365))

df = pd.DataFrame({"ds": dates, "y": sales})

model = Prophet(yearly_seasonality=False, weekly_seasonality=True)
model.fit(df)

future   = model.make_future_dataframe(periods=30)
forecast = model.predict(future)

print(forecast[["ds", "yhat", "yhat_lower", "yhat_upper"]].tail(5))

À explorer : model.add_country_holidays(country_name='FR') : observez l'impact sur les prévisions des jours fériés français.


5. XGBoost pour le forecasting : features temporelles

import pandas as pd, numpy as np
from xgboost import XGBRegressor

def create_features(df):
    df = df.copy()
    df["day_of_week"] = df.index.dayofweek
    df["month"]       = df.index.month
    df["lag_1"]       = df["y"].shift(1)
    df["lag_7"]       = df["y"].shift(7)
    df["rolling_7"]   = df["y"].shift(1).rolling(7).mean()
    return df.dropna()

df_feat = create_features(df.set_index("ds"))
X = df_feat.drop("y", axis=1)
y = df_feat["y"]

model = XGBRegressor(n_estimators=200, learning_rate=0.05, max_depth=4)
model.fit(X, y)

Les lags transforment un problème temporel en régression supervisée standard : XGBoost peut alors exploiter toute sa puissance.


6. Validation temporelle : pourquoi le split classique est faux

Ne jamais utiliser train_test_split aléatoire sur une série temporelle. Cela entraîne une fuite de données : le modèle voit des données futures pendant l'entraînement.

from sklearn.model_selection import TimeSeriesSplit
from sklearn.metrics import mean_absolute_error
import numpy as np

tscv = TimeSeriesSplit(n_splits=5)
scores = []

for fold, (train_idx, test_idx) in enumerate(tscv.split(X)):
    X_tr, X_te = X.iloc[train_idx], X.iloc[test_idx]
    y_tr, y_te = y.iloc[train_idx], y.iloc[test_idx]
    model.fit(X_tr, y_tr)
    mae = mean_absolute_error(y_te, model.predict(X_te))
    scores.append(mae)
    print(f"Fold {fold+1} MAE : {mae:.2f}")

print(f"\nMAE moyen : {np.mean(scores):.2f} ± {np.std(scores):.2f}")

7. Métriques d'évaluation

MétriqueFormuleInterprétation
MAE`mean(y - ŷ
RMSEsqrt(mean((y-ŷ)²))Pénalise les grosses erreurs
MAPE`mean(y-ŷ
SMAPESymétrique MAPERobuste aux valeurs proches de 0

MAPE est trompeuse quand les valeurs réelles sont proches de 0. Préférez MAE ou SMAPE dans ce cas.


Quelle approche choisir ?

SituationRecommandation
Exploration rapideProphet
Saisonnalité complexe + jours fériésProphet ou SARIMA
Features exogènes nombreusesXGBoost avec lags
Plusieurs séries similairesLightGBM global model
Haute précisionEnsemble Prophet + XGBoost

Specialiste IA — Master Intelligence Artificielle

Diplome d'un Master en Intelligence Artificielle, je travaille au quotidien sur des projets IA en entreprise. J'ai cree IwanttolearnAI pour rendre l'apprentissage de l'IA accessible a tous, gratuitement.