Séries Temporelles avec Pandas 3.0 : De la Manipulation à la Prévision

Maîtrisez l'analyse de séries temporelles avec Pandas 3.0 en Python : resampling, rolling windows, ARIMA, SARIMA et Prophet. Code prêt à l'emploi et bonnes pratiques pour vos projets de prévision.

Introduction : Pourquoi les Séries Temporelles Sont Partout en 2026

Prix de l'énergie, trafic réseau, ventes e-commerce, capteurs IoT, cours de crypto — si vos données ont une dimension temporelle, vous faites déjà de l'analyse de séries temporelles sans forcément le savoir. Et honnêtement, en 2026, avec l'explosion des données temps réel et des besoins en prévision, maîtriser cette compétence n'est plus optionnel pour un data scientist ou un analyste Python. C'est devenu un prérequis.

La bonne nouvelle ? Pandas 3.0, sorti en janvier 2026, apporte des améliorations majeures pour le travail avec les données temporelles : résolution en microsecondes par défaut, nouveaux offsets semestriels, et bien sûr toutes les optimisations PyArrow et Copy-on-Write qui rendent le traitement plus rapide et plus sûr. Si vous avez déjà pesté contre OutOfBoundsDatetime, vous allez apprécier.

Dans ce guide, on part de zéro et on couvre l'ensemble du workflow : charger et indexer des séries temporelles, les explorer visuellement, les transformer (resampling, rolling, shifting), tester leur stationnarité, puis construire des modèles de prévision avec ARIMA/SARIMA (statsmodels) et Prophet. Le tout avec du code fonctionnel que vous pouvez copier-coller directement.

Si vous avez lu nos précédents articles sur le nettoyage de données avec Pandas 3.0 ou la visualisation de données en Python, celui-ci s'inscrit comme la suite logique. Vos données sont propres, vous savez les visualiser — maintenant, on va les faire parler dans le temps.

Ce que Pandas 3.0 Change pour les Séries Temporelles

Avant de plonger dans le code, prenons un moment pour comprendre ce que Pandas 3.0 apporte spécifiquement aux données temporelles. Ce ne sont pas de simples ajustements cosmétiques — certains changements vont réellement modifier vos habitudes.

Résolution Microseconde par Défaut

C'est LE changement le plus impactant pour les séries temporelles. Avant Pandas 3.0, la résolution par défaut était la nanoseconde, ce qui limitait la plage de dates à 1678–2262. Si vous avez déjà rencontré la fameuse erreur OutOfBoundsDatetime en travaillant avec des données historiques longues, c'est terminé. Fini, envolé.

import pandas as pd

# Pandas 3.0 : résolution microseconde par défaut
ts = pd.Timestamp("1200-01-01")
print(ts)  # Fonctionne ! Plus d'erreur OutOfBoundsDatetime

# Vérifier la résolution
dates = pd.to_datetime(["2024-01-01", "2025-06-15", "2026-03-01"])
print(dates.dtype)  # datetime64[us] — microsecondes

En pratique, la microseconde suffit largement pour 99 % des cas d'usage en data science. Et si vous avez réellement besoin de la nanoseconde (données de trading haute fréquence par exemple), vous pouvez toujours la spécifier explicitement avec dtype="datetime64[ns]". Mais soyons honnêtes, la plupart d'entre nous n'en auront jamais besoin.

Nouveaux Offsets Semestriels

Pandas 3.0 introduit quatre nouvelles classes d'offset pour les périodes semestrielles : HalfYearBegin, HalfYearEnd, BHalfYearBegin et BHalfYearEnd. Si vous bossez avec des données financières ou des rapports semestriels, c'est un ajout franchement bienvenu :

from pandas.tseries.offsets import HalfYearEnd

# Créer un index semestriel
idx = pd.date_range("2024-01-01", periods=6, freq=HalfYearEnd())
print(idx)
# DatetimeIndex(['2024-06-30', '2024-12-31', '2025-06-30',
#                '2025-12-31', '2026-06-30', '2026-12-31'])

Copy-on-Write et Sécurité des Transformations

Avec Copy-on-Write activé par défaut, vos opérations de resampling, shifting et rolling ne risquent plus de modifier accidentellement le DataFrame source. C'est un filet de sécurité précieux quand on chaîne beaucoup d'opérations temporelles — et croyez-moi, quand on débogue un pipeline qui a muté un DataFrame quelque part sans prévenir, on apprécie.

Charger et Indexer des Séries Temporelles

La première étape de toute analyse temporelle, c'est de s'assurer que vos données sont correctement indexées par le temps. Ça a l'air évident, mais c'est là que beaucoup de projets démarrent du mauvais pied. Voyons les différents cas de figure.

Lecture depuis un Fichier CSV

import pandas as pd

# Méthode recommandée : parse_dates + index_col à la lecture
df = pd.read_csv(
    "ventes_mensuelles.csv",
    parse_dates=["date"],
    index_col="date"
)

print(df.index)
# DatetimeIndex(['2020-01-01', '2020-02-01', ...], dtype='datetime64[us]', name='date', freq=None)
print(type(df.index))
# 

Le paramètre parse_dates convertit automatiquement la colonne en datetime, et index_col en fait l'index du DataFrame. C'est la combinaison magique pour travailler efficacement avec les séries temporelles. Prenez l'habitude de le faire dès la lecture — ça vous évitera pas mal de galères ensuite.

Conversion Manuelle si Nécessaire

Parfois le CSV n'est pas aussi propre qu'on le voudrait. Pas de panique :

# Si la colonne n'est pas au bon format
df["date"] = pd.to_datetime(df["date"], format="%d/%m/%Y")
df = df.set_index("date").sort_index()

# Vérifier que l'index est bien un DatetimeIndex
assert isinstance(df.index, pd.DatetimeIndex)

Créer des Données Temporelles de Toutes Pièces

Pour suivre les exemples de cet article sans avoir de jeu de données sous la main, voici comment générer un dataset synthétique mais réaliste :

import numpy as np

# Générer un jeu de données synthétique réaliste
np.random.seed(42)
dates = pd.date_range("2020-01-01", "2026-01-01", freq="D")
n = len(dates)

# Tendance + saisonnalité + bruit
tendance = np.linspace(100, 250, n)
saisonnalite = 30 * np.sin(2 * np.pi * np.arange(n) / 365.25)
bruit = np.random.normal(0, 10, n)

ventes = tendance + saisonnalite + bruit

df = pd.DataFrame({"ventes": ventes}, index=dates)
df.index.name = "date"
print(df.head())

Exploiter l'Accesseur dt

L'accesseur .dt permet d'extraire des composantes temporelles utiles pour l'analyse exploratoire. C'est un de ces outils qu'on sous-estime jusqu'au jour où on découvre à quel point il simplifie les choses :

# Extraire des features temporelles
df["annee"] = df.index.year
df["mois"] = df.index.month
df["jour_semaine"] = df.index.dayofweek
df["trimestre"] = df.index.quarter

# Analyser les ventes par mois
ventes_par_mois = df.groupby("mois")["ventes"].mean()
print(ventes_par_mois)

Explorer et Visualiser les Séries Temporelles

Avant de modéliser quoi que ce soit, il faut regarder ses données. C'est une étape qu'on a tendance à survoler (j'ai moi-même été coupable de ça plus d'une fois), et c'est presque toujours une erreur.

Visualisation de Base

import matplotlib.pyplot as plt

fig, ax = plt.subplots(figsize=(14, 5))
ax.plot(df.index, df["ventes"], linewidth=0.8, color="#2563eb")
ax.set_title("Ventes journalières (2020-2026)", fontsize=14)
ax.set_xlabel("Date")
ax.set_ylabel("Ventes (unités)")
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

Décomposition de la Série

La décomposition permet de séparer les trois composantes fondamentales : tendance, saisonnalité et résidu (bruit). Honnêtement, c'est l'outil de diagnostic numéro un — celui qu'il faut lancer en premier.

from statsmodels.tsa.seasonal import seasonal_decompose

# Resampler en données mensuelles pour une décomposition plus lisible
df_mensuel = df["ventes"].resample("ME").mean()

decomposition = seasonal_decompose(df_mensuel, model="additive", period=12)

fig = decomposition.plot()
fig.set_size_inches(14, 10)
fig.suptitle("Décomposition de la série temporelle", fontsize=14, y=1.02)
plt.tight_layout()
plt.show()

Le modèle additive suppose que les composantes s'additionnent : Y(t) = Tendance(t) + Saisonnalité(t) + Résidu(t). Si l'amplitude de la saisonnalité augmente avec le niveau de la série, utilisez plutôt model="multiplicative". Un bon réflexe : regardez le graphique brut — si les oscillations grandissent au fil du temps, c'est multiplicatif.

Transformer les Séries : Resampling, Rolling et Shifting

Ces trois opérations constituent la boîte à outils fondamentale du travail avec les séries temporelles en Pandas. Maîtrisez-les, et vous pourrez répondre à la majorité des questions analytiques. Allez, on les passe en revue.

Resampling (Rééchantillonnage)

Le resampling permet de changer la fréquence de vos données — agréger du journalier au mensuel, ou interpoler du mensuel au journalier.

# Downsampling : journalier -> mensuel
ventes_mensuelles = df["ventes"].resample("ME").agg(["mean", "sum", "std"])
print(ventes_mensuelles.head())

# Downsampling : journalier -> trimestriel
ventes_trim = df["ventes"].resample("QE").sum()

# Upsampling : mensuel -> journalier avec interpolation
df_mensuel_up = df_mensuel.resample("D").interpolate(method="linear")

Les codes de fréquence courants : "D" (jour), "W" (semaine), "ME" (fin de mois), "MS" (début de mois), "QE" (fin de trimestre), "YE" (fin d'année). Attention : Pandas 3.0 utilise "ME" au lieu de l'ancien "M" — on y reviendra dans les pièges à éviter.

Rolling Windows (Fenêtres Glissantes)

Les moyennes et écarts-types glissants sont essentiels pour lisser le bruit et détecter les tendances. C'est un peu le couteau suisse de l'analyse temporelle.

# Moyenne mobile sur 30 jours
df["rolling_30"] = df["ventes"].rolling(window=30).mean()

# Moyenne mobile sur 90 jours pour la tendance
df["rolling_90"] = df["ventes"].rolling(window=90).mean()

# Écart-type glissant (mesure de volatilité)
df["rolling_std_30"] = df["ventes"].rolling(window=30).std()

# Visualiser
fig, ax = plt.subplots(figsize=(14, 5))
ax.plot(df.index, df["ventes"], alpha=0.3, label="Données brutes")
ax.plot(df.index, df["rolling_30"], label="Moyenne mobile 30j", linewidth=2)
ax.plot(df.index, df["rolling_90"], label="Moyenne mobile 90j", linewidth=2)
ax.legend()
ax.set_title("Ventes avec moyennes mobiles")
plt.tight_layout()
plt.show()

Shifting (Décalage Temporel)

Le shifting permet de comparer une valeur avec ses valeurs passées — indispensable pour calculer des variations et créer des features de lag.

# Décaler d'une période (lag)
df["ventes_hier"] = df["ventes"].shift(1)

# Variation journalière
df["variation_jour"] = df["ventes"] - df["ventes"].shift(1)

# Variation en pourcentage
df["pct_change"] = df["ventes"].pct_change() * 100

# Comparaison avec la même date l'année précédente
df["ventes_an_prec"] = df["ventes"].shift(365)
df["croissance_annuelle"] = (
    (df["ventes"] - df["ventes_an_prec"]) / df["ventes_an_prec"] * 100
)

Tester la Stationnarité : Une Étape Indispensable

Avant de construire un modèle ARIMA, il faut vérifier si la série est stationnaire — c'est-à-dire si ses propriétés statistiques (moyenne, variance) ne changent pas dans le temps. Spoiler : la plupart des séries réelles ne le sont pas, et il faut les transformer.

Le Test de Dickey-Fuller Augmenté (ADF)

from statsmodels.tsa.stattools import adfuller

def test_stationnarite(serie, nom=""):
    """Effectue le test ADF et affiche les résultats."""
    resultat = adfuller(serie.dropna(), autolag="AIC")

    print(f"=== Test ADF : {nom} ===")
    print(f"Statistique ADF : {resultat[0]:.4f}")
    print(f"p-value :          {resultat[1]:.6f}")
    print(f"Lags utilisés :    {resultat[2]}")
    print(f"Observations :     {resultat[3]}")
    print("Valeurs critiques :")
    for seuil, valeur in resultat[4].items():
        print(f"  {seuil}: {valeur:.4f}")

    if resultat[1] < 0.05:
        print("-> La série EST stationnaire (p < 0.05)")
    else:
        print("-> La série N'EST PAS stationnaire (p >= 0.05)")
    print()

# Tester la série brute
test_stationnarite(df_mensuel, "Ventes mensuelles brutes")

# Tester après différenciation d'ordre 1
diff_1 = df_mensuel.diff().dropna()
test_stationnarite(diff_1, "Ventes mensuelles (diff ordre 1)")

Si la p-value est inférieure à 0.05, on rejette l'hypothèse nulle : la série est considérée comme stationnaire. Sinon, il faut la différencier (une ou plusieurs fois) avant de la modéliser. Dans mon expérience, une seule différenciation suffit dans la majorité des cas.

Visualiser ACF et PACF

Les graphiques d'autocorrélation (ACF) et d'autocorrélation partielle (PACF) aident à déterminer les paramètres p et q du modèle ARIMA. C'est un peu de l'art autant que de la science, il faut le reconnaître.

from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

fig, axes = plt.subplots(1, 2, figsize=(14, 4))

plot_acf(diff_1, lags=24, ax=axes[0], title="ACF — Série différenciée")
plot_pacf(diff_1, lags=24, ax=axes[1], title="PACF — Série différenciée")

plt.tight_layout()
plt.show()

En résumé : le nombre de lags significatifs dans le PACF donne une estimation de p (ordre AR), et le nombre de lags significatifs dans l'ACF donne une estimation de q (ordre MA). Si ça vous semble flou, pas d'inquiétude — on verra auto_arima juste après, qui fait ce travail pour vous.

Modélisation avec ARIMA et SARIMA

ARIMA est le modèle classique de référence pour la prévision de séries temporelles. Il combine trois composantes : AutoRégression (AR), Intégration (I) pour la différenciation, et Moyenne Mobile (MA). SARIMA étend ARIMA en ajoutant une composante saisonnière. Passons à la pratique.

Préparer les Données : Split Temporel

Un point crucial avant tout : avec des séries temporelles, on ne fait jamais de split aléatoire. Jamais. Le modèle s'entraîne sur le passé et prédit le futur, point.

# Split temporel — JAMAIS de split aléatoire pour les séries temporelles !
date_split = "2025-06-01"
train = df_mensuel[:date_split]
test = df_mensuel[date_split:]

print(f"Entraînement : {train.index[0]} -> {train.index[-1]} ({len(train)} mois)")
print(f"Test :          {test.index[0]} -> {test.index[-1]} ({len(test)} mois)")

ARIMA Simple

from statsmodels.tsa.arima.model import ARIMA

# Ajuster un modèle ARIMA(1,1,1)
model_arima = ARIMA(train, order=(1, 1, 1))
resultat_arima = model_arima.fit()

print(resultat_arima.summary())

# Prévisions sur la période de test
previsions = resultat_arima.forecast(steps=len(test))

# Visualiser
fig, ax = plt.subplots(figsize=(14, 5))
ax.plot(train.index, train, label="Entraînement")
ax.plot(test.index, test, label="Réel (test)", color="green")
ax.plot(test.index, previsions, label="Prévisions ARIMA(1,1,1)",
        color="red", linestyle="--")
ax.legend()
ax.set_title("Prévisions ARIMA vs Réalité")
plt.tight_layout()
plt.show()

SARIMA pour la Saisonnalité

Nos données de ventes présentent une saisonnalité annuelle évidente. ARIMA seul ne capture pas cette composante — il faut passer à SARIMA. C'est là que les choses deviennent intéressantes.

from statsmodels.tsa.statespace.sarimax import SARIMAX

# SARIMA(1,1,1)(1,1,1,12) — composante saisonnière de période 12
model_sarima = SARIMAX(
    train,
    order=(1, 1, 1),
    seasonal_order=(1, 1, 1, 12),
    enforce_stationarity=False,
    enforce_invertibility=False
)
resultat_sarima = model_sarima.fit(disp=False)

print(resultat_sarima.summary())

# Prévisions
prev_sarima = resultat_sarima.forecast(steps=len(test))

# Intervalle de confiance
prev_ci = resultat_sarima.get_forecast(steps=len(test))
ci = prev_ci.conf_int()

# Visualiser avec intervalle de confiance
fig, ax = plt.subplots(figsize=(14, 5))
ax.plot(train.index, train, label="Entraînement")
ax.plot(test.index, test, label="Réel (test)", color="green")
ax.plot(test.index, prev_sarima, label="SARIMA(1,1,1)(1,1,1,12)",
        color="red", linestyle="--")
ax.fill_between(ci.index, ci.iloc[:, 0], ci.iloc[:, 1],
                color="red", alpha=0.1, label="IC 95%")
ax.legend()
ax.set_title("Prévisions SARIMA avec intervalle de confiance")
plt.tight_layout()
plt.show()

Auto-ARIMA avec pmdarima

Plutôt que de deviner les paramètres (ce qui, avouons-le, demande pas mal d'expérience), pmdarima teste automatiquement des combinaisons et sélectionne la meilleure selon le critère AIC :

import pmdarima as pm

auto_model = pm.auto_arima(
    train,
    seasonal=True,
    m=12,               # période saisonnière
    stepwise=True,       # recherche heuristique (plus rapide)
    suppress_warnings=True,
    trace=True           # afficher la progression
)

print(auto_model.summary())
print(f"\nMeilleur modèle : {auto_model.order} x {auto_model.seasonal_order}")

# Prévisions
prev_auto = pd.Series(
    auto_model.predict(n_periods=len(test)),
    index=test.index
)

Prévision Rapide avec Prophet

Si vous cherchez une solution rapide et robuste sans trop vous prendre la tête sur les paramètres, Prophet (Meta) est fait pour ça. La version 1.3.0, sortie en janvier 2026, supporte désormais nativement Pandas 3.0 et NumPy 2.4. C'est l'outil que je recommande souvent pour un premier prototype.

Préparation des Données pour Prophet

Prophet attend un DataFrame avec exactement deux colonnes : ds (date) et y (valeur). Pas de négociation là-dessus.

from prophet import Prophet

# Préparer les données au format Prophet
df_prophet = df_mensuel.reset_index()
df_prophet.columns = ["ds", "y"]

# Split
train_prophet = df_prophet[df_prophet["ds"] < date_split]
test_prophet = df_prophet[df_prophet["ds"] >= date_split]

# Ajuster le modèle
model_prophet = Prophet(
    yearly_seasonality=True,
    weekly_seasonality=False,  # données mensuelles
    daily_seasonality=False
)
model_prophet.fit(train_prophet)

# Créer les dates futures et prédire
future = model_prophet.make_future_dataframe(periods=len(test), freq="ME")
previsions_prophet = model_prophet.predict(future)

# Visualiser les composantes
model_prophet.plot_components(previsions_prophet)
plt.show()

Visualiser les Prévisions Prophet

fig = model_prophet.plot(previsions_prophet)
plt.title("Prévisions Prophet")
plt.tight_layout()
plt.show()

L'un des gros avantages de Prophet, c'est qu'il gère automatiquement les changements de tendance (changepoints) et fournit des intervalles d'incertitude par défaut. C'est aussi un excellent outil de communication : les graphiques de décomposition (tendance + saisonnalité + jours fériés) sont immédiatement compréhensibles par les parties prenantes non techniques. J'ai vu des réunions de direction où un graphique Prophet a fait plus que dix slides PowerPoint.

Évaluer et Comparer les Modèles

Un modèle de prévision ne vaut rien sans une évaluation rigoureuse. On peut avoir le modèle le plus sophistiqué du monde — si on ne mesure pas sa performance correctement, on navigue à l'aveugle.

Métriques d'Évaluation

from sklearn.metrics import mean_absolute_error, mean_squared_error
import numpy as np

def evaluer_previsions(reel, prevu, nom_modele):
    """Calcule et affiche les métriques d'évaluation."""
    mae = mean_absolute_error(reel, prevu)
    rmse = np.sqrt(mean_squared_error(reel, prevu))
    mape = np.mean(np.abs((reel - prevu) / reel)) * 100

    print(f"=== {nom_modele} ===")
    print(f"MAE  : {mae:.2f}")
    print(f"RMSE : {rmse:.2f}")
    print(f"MAPE : {mape:.2f}%")
    print()
    return {"MAE": mae, "RMSE": rmse, "MAPE": mape}

# Comparer les modèles
r_arima = evaluer_previsions(test, previsions, "ARIMA(1,1,1)")
r_sarima = evaluer_previsions(test, prev_sarima, "SARIMA(1,1,1)(1,1,1,12)")
r_auto = evaluer_previsions(test, prev_auto, f"Auto-ARIMA {auto_model.order}")

# Prophet : aligner les prévisions sur les dates de test
prev_prophet_aligned = previsions_prophet.set_index("ds").loc[test.index, "yhat"]
r_prophet = evaluer_previsions(test, prev_prophet_aligned, "Prophet")

Tableau Comparatif

resultats = pd.DataFrame({
    "ARIMA": r_arima,
    "SARIMA": r_sarima,
    "Auto-ARIMA": r_auto,
    "Prophet": r_prophet
}).T

print(resultats.to_string())
print(f"\nMeilleur modèle (MAPE) : {resultats['MAPE'].idxmin()}")

Quelle métrique choisir ? La MAPE (Mean Absolute Percentage Error) est souvent la plus parlante pour les décideurs car elle s'exprime en pourcentage. Le RMSE pénalise davantage les grosses erreurs. Le MAE est le plus robuste aux outliers. Mon conseil : regardez les trois, mais utilisez la MAPE quand vous présentez vos résultats à des non-techniciens.

Validation Croisée Temporelle

Un simple split train/test peut donner des résultats trompeurs — votre modèle pourrait être bon sur cette période précise et médiocre sur d'autres. La validation croisée temporelle (time series cross-validation) est bien plus robuste :

from sklearn.model_selection import TimeSeriesSplit

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

for i, (train_idx, test_idx) in enumerate(tscv.split(df_mensuel)):
    train_cv = df_mensuel.iloc[train_idx]
    test_cv = df_mensuel.iloc[test_idx]

    model_cv = SARIMAX(
        train_cv,
        order=(1, 1, 1),
        seasonal_order=(1, 1, 1, 12),
        enforce_stationarity=False,
        enforce_invertibility=False
    )
    res_cv = model_cv.fit(disp=False)
    prev_cv = res_cv.forecast(steps=len(test_cv))

    mae_cv = mean_absolute_error(test_cv, prev_cv)
    scores_mae.append(mae_cv)
    print(f"Fold {i+1}: MAE = {mae_cv:.2f}")

print(f"\nMAE moyen (5 folds) : {np.mean(scores_mae):.2f} +/- {np.std(scores_mae):.2f}")

L'important avec TimeSeriesSplit : contrairement à un KFold classique, il respecte l'ordre chronologique. L'ensemble d'entraînement est toujours antérieur à l'ensemble de test. C'est absolument indispensable pour éviter le data leakage temporel — un piège dans lequel même des data scientists expérimentés tombent parfois.

Bonnes Pratiques et Pièges à Éviter

Après avoir couvert les outils, voici les erreurs les plus fréquentes que je vois sur des projets en production — et comment les éviter. Certaines semblent évidentes, mais elles reviennent sans cesse.

1. Ne Jamais Faire de Split Aléatoire

Je l'ai déjà dit, mais ça vaut la peine de le répéter. Avec des séries temporelles, un split aléatoire introduit du data leakage : le modèle « voit » le futur pendant l'entraînement. Utilisez toujours un split chronologique ou TimeSeriesSplit.

2. Vérifier la Fréquence de l'Index

# Si freq est None, statsmodels peut planter
print(df_mensuel.index.freq)  # None ? Il faut la spécifier :
df_mensuel = df_mensuel.asfreq("ME")
print(df_mensuel.index.freq)  # 

3. Gérer les Valeurs Manquantes Avant la Modélisation

# Vérifier
print(df_mensuel.isna().sum())

# Interpoler si nécessaire
df_mensuel = df_mensuel.interpolate(method="time")

4. Attention aux Codes de Fréquence Pandas 3.0

Pandas 3.0 a renommé certains codes de fréquence. Les anciens alias sont dépréciés et vont finir par provoquer des erreurs :

  • "M" devient "ME" (fin de mois)
  • "Q" devient "QE" (fin de trimestre)
  • "Y" devient "YE" (fin d'année)
  • "MS", "QS", "YS" restent inchangés (début de période)

Si vous migrez du code existant vers Pandas 3.0, faites un rechercher-remplacer global sur ces alias. Ça vous évitera des surprises.

5. Logger et Versionner vos Modèles

En production, sauvegardez vos modèles entraînés et les métriques associées. Un pickle simple peut suffire pour un projet personnel, mais des outils comme MLflow offrent un suivi bien plus structuré des expériences. Croyez-moi, quand il faudra expliquer pourquoi votre modèle du mois dernier donnait de meilleurs résultats, vous serez content d'avoir tout loggé.

Récapitulatif : Quel Modèle Choisir ?

Voici un guide rapide pour choisir le bon outil selon votre situation :

  • ARIMA : série sans saisonnalité marquée, bon contrôle des paramètres, interprétabilité.
  • SARIMA : série avec saisonnalité claire, besoin de modéliser explicitement la composante saisonnière.
  • Auto-ARIMA (pmdarima) : quand vous ne savez pas quels paramètres choisir, ou pour un prototypage rapide.
  • Prophet : prototypage rapide, communication aux parties prenantes, données avec changements de tendance et effets de jours fériés.
  • LSTM / Deep Learning : données massives, patterns très complexes, quand les modèles classiques ne suffisent plus (mais attention au coût de développement).

En pratique, commencez par SARIMA ou Prophet, évaluez leurs performances, et ne passez à des modèles plus complexes que si les résultats ne sont pas satisfaisants. La simplicité a du bon.

FAQ

Quelle est la différence entre ARIMA et SARIMA ?

ARIMA modélise la tendance et le bruit d'une série temporelle, mais ne capture pas la saisonnalité. SARIMA est une extension d'ARIMA qui ajoute des paramètres saisonniers (P, D, Q, s) pour modéliser les patterns qui se répètent à intervalles réguliers (par exemple tous les 12 mois). Si vos données montrent un cycle saisonnier, utilisez SARIMA.

Comment savoir si ma série temporelle est stationnaire ?

Utilisez le test de Dickey-Fuller augmenté (ADF) disponible dans statsmodels. Si la p-value est inférieure à 0.05, la série est considérée stationnaire. Sinon, appliquez une différenciation (une ou plusieurs fois) avec .diff() et retestez. Visuellement, une série stationnaire a une moyenne et une variance constantes dans le temps.

Faut-il utiliser Prophet ou ARIMA pour mes prévisions ?

Ça dépend de votre contexte. Prophet est idéal pour un prototypage rapide, des données avec des changements de tendance fréquents, ou quand vous devez communiquer les résultats à des non-techniciens. ARIMA/SARIMA offre plus de contrôle et de flexibilité, et fonctionne souvent mieux sur des séries bien comprises avec une saisonnalité régulière. En pratique, testez les deux et comparez les métriques (MAE, RMSE, MAPE).

Pourquoi Pandas 3.0 utilise la microseconde au lieu de la nanoseconde ?

La résolution nanoseconde limitait la plage de dates supportée entre 1678 et 2262, provoquant des erreurs OutOfBoundsDatetime fréquentes. La microseconde étend cette plage à plusieurs centaines de milliers d'années, ce qui couvre tous les cas d'usage courants. Si vous avez besoin de la nanoseconde (trading haute fréquence), vous pouvez toujours la spécifier avec dtype="datetime64[ns]".

Comment éviter le data leakage dans l'analyse de séries temporelles ?

Le piège principal est d'utiliser un split aléatoire (comme train_test_split de scikit-learn) au lieu d'un split chronologique. Pour les séries temporelles, utilisez toujours TimeSeriesSplit ou un split manuel où les données d'entraînement sont strictement antérieures aux données de test. Veillez aussi à ne pas utiliser de features calculées à partir de données futures (par exemple, une moyenne mobile centrée au lieu d'une moyenne mobile rétrospective).

À propos de l'auteur Editorial Team

Our team of expert writers and editors.