Séries temporelles, signaux et durées de vie
Dès que le temps entre en jeu, l'hypothèse d'indépendance des observations — sur laquelle repose tout le reste du cours — tombe. Validation croisée, tests statistiques, feature engineering : tout doit être repensé. Ce module couvre les trois familles de problèmes temporels que l'on rencontre réellement : prévoir une trajectoire, analyser un signal, et estimer une durée avant événement.
📋 Au programme
- Ce que le temps change
- Décomposition et stationnarité
- Lire une ACF et une PACF
- Modèles classiques : ETS et ARIMA
- Approche ML : variables et gradient boosting
- Deep learning et modèles de fondation
- Prévision probabiliste et évaluation
- Espace d'états et filtre de Kalman
- Ruptures et anomalies
- Analyse spectrale et filtrage
- Durées de vie, censure et fiabilité
1. Ce que le temps change
Autocorrélation les observations voisines se ressemblent : la taille d'échantillon
EFFECTIVE est bien inférieure à n. Un test qui l'ignore déclare
significatif ce qui ne l'est pas (module 9).
Non-stationnarité moyenne, variance et saisonnalité évoluent. Le passé lointain
peut être trompeur plutôt qu'informatif.
Ordre imposé entraîner sur le futur pour prédire le passé n'a aucun sens :
la validation devient séquentielle (module 12).
Horizon prévoir à J+1 et à J+30 sont deux problèmes différents, avec des
variables et des performances différentes.L'autocorrélation, concrètement
Si la température d'aujourd'hui ressemble fortement à celle d'hier, 365 mesures quotidiennes ne contiennent pas 365 informations indépendantes — peut-être l'équivalent de trente. Toutes les formules du module 9 en \(\sqrt{n}\) deviennent alors optimistes : un intervalle de confiance calculé naïvement sur des données autocorrélées est beaucoup trop étroit, et l'on conclut à des effets qui n'existent pas. C'est la raison pour laquelle on ne peut pas appliquer directement les outils des modules précédents à une série temporelle.
2. Décomposition et stationnarité
Une série se lit d'abord comme la somme (ou le produit) de trois composantes : tendance (l'évolution de fond), saisonnalité (le motif qui se répète à période fixe) et résidu (ce qui reste). La décomposition STL, par lissage local, est l'outil de référence : robuste aux valeurs aberrantes, elle accepte une saisonnalité qui évolue lentement.
import polars as pl, pandas as pd
from statsmodels.tsa.seasonal import STL
from statsmodels.tsa.stattools import adfuller, kpss
serie = pd.read_csv("conso.csv", index_col="date", parse_dates=True)["valeur"].asfreq("D")
res = STL(serie, period=7, robust=True).fit()
res.plot() # tendance, saison, résidu
print("ADF p =", adfuller(serie)[1]) # H0 = racine unitaire (NON stationnaire)
print("KPSS p =", kpss(serie, regression="c")[1]) # H0 = stationnaritéUne série est stationnaire si ses propriétés statistiques ne dépendent pas de la date : même moyenne, même variance, même structure de dépendance à tout moment. Les modèles classiques l'exigent, parce qu'ils estiment des coefficients supposés constants. On s'y ramène par différenciation (\(\nabla y_t = y_t - y_{t-1}\), qui élimine une tendance linéaire), différenciation saisonnière (\(y_t - y_{t-s}\)) ou transformation stabilisante (logarithme si la variance croît avec le niveau).
Utiliser ADF et KPSS ensemble est plus sûr : leurs hypothèses nulles sont inversées, donc un désaccord signale une situation ambiguë qu'il vaut mieux examiner graphiquement plutôt que trancher mécaniquement.
3. Lire une ACF et une PACF
L'autocorrélation (ACF) au décalage \(k\) mesure la corrélation entre la série et elle-même décalée de \(k\) pas. La PACF mesure la même chose en retirant l'effet des décalages intermédiaires — la corrélation directe entre \(y_t\) et \(y_{t-k}\), une fois les \(k-1\) précédents pris en compte.
ACF qui décroît TRÈS LENTEMENT → série non stationnaire : différencier
ACF avec un pic à 7, 14, 21… → saisonnalité hebdomadaire
ACF qui se coupe net après q → processus MA(q)
PACF qui se coupe net après p → processus AR(p)
ACF et PACF décroissant toutes deux → ARMA mixte : laisser l'auto-sélection choisir
ACF │█ PACF │█
│█ █ │█
│█ █ █ ▄ │█ ▄
│█ █ █ █ ▄ ▂ │─ ─ ─ ─ ─ ─ ← coupure après 2
└──────────────► décalage └──────────────► décalage
décroissance lente = AR → AR(2)from statsmodels.graphics.tsaplots import plot_acf, plot_pacf plot_acf(serie.diff().dropna(), lags=40) # sur la série DIFFÉRENCIÉE plot_pacf(serie.diff().dropna(), lags=40)
4. Modèles classiques : ETS et ARIMA
Lissage exponentiel (ETS) — l'idée tient en une ligne : une moyenne pondérée du passé dont les poids décroissent géométriquement, de sorte que le passé récent compte davantage. Holt-Winters ajoute une tendance et une saisonnalité, chacune avec son propre coefficient de lissage :
où \(\ell\) est le niveau, \(b\) la pente et \(s\) la composante saisonnière. Simple, rapide, et étonnamment difficile à battre sur des séries métier courtes et régulières.
ARIMA(p,d,q) — \(d\) différenciations pour se ramener à la stationnarité, \(p\) termes autorégressifs (le passé de la série) et \(q\) termes de moyenne mobile (le passé des erreurs) :
La partie AR dit « la valeur d'aujourd'hui ressemble à celles d'hier » ; la partie MA dit « l'erreur d'aujourd'hui ressemble à celles d'hier », ce qui capte les chocs dont l'effet se dissipe. SARIMA ajoute les mêmes termes à la fréquence saisonnière, SARIMAX ajoute des régresseurs externes.
from statsforecast import StatsForecast
from statsforecast.models import AutoARIMA, AutoETS, SeasonalNaive
sf = StatsForecast(
models=[AutoARIMA(season_length=7), AutoETS(season_length=7),
SeasonalNaive(season_length=7)], # LA baseline à battre
freq="D", n_jobs=-1,
)
sf.fit(df) # df : unique_id, ds, y
prev = sf.forecast(h=28, level=[80, 95]) # avec intervalles de prédiction
print(prev.head())Quand les modèles classiques battent le machine learning
Systématiquement quand : la série est courte (moins de quelques centaines de points), il y en a peu (une ou dix, pas dix mille), la structure est régulière, et il faut des intervalles de prévision fiables. Les compétitions M4 et M5 l'ont confirmé : les méthodes statistiques simples, et surtout les combinaisons de méthodes simples, restent redoutables. Le ML prend l'avantage quand on doit prévoir des milliers de séries apparentées simultanément, avec beaucoup de régresseurs externes — une chaîne de magasins, un parc de capteurs — parce qu'il apprend alors des motifs communs à toutes les séries.
5. Approche ML : variables et gradient boosting
On transforme la prévision en régression tabulaire en construisant des variables exclusivement passées, puis on applique le module 14.
import numpy as np, polars as pl
df = (
df.sort("date")
.with_columns(
# décalages : la valeur d'il y a 1, 7 et 364 jours (même jour de semaine)
*[pl.col("y").shift(k).over("serie_id").alias(f"lag_{k}") for k in (1, 7, 364)],
# moyennes glissantes sur le PASSÉ uniquement — le shift(1) est ESSENTIEL
pl.col("y").shift(1).rolling_mean(7).over("serie_id").alias("ma_7"),
pl.col("y").shift(1).rolling_mean(28).over("serie_id").alias("ma_28"),
pl.col("y").shift(1).rolling_std(28).over("serie_id").alias("sd_28"),
# tendance courte : rapport des deux moyennes
(pl.col("y").shift(1).rolling_mean(7) /
pl.col("y").shift(1).rolling_mean(28)).over("serie_id").alias("ratio_7_28"),
# calendrier et saisonnalité cyclique (module 12)
pl.col("date").dt.weekday().alias("jour_semaine"),
(2 * np.pi * pl.col("date").dt.ordinal_day() / 365.25).sin().alias("an_sin"),
(2 * np.pi * pl.col("date").dt.ordinal_day() / 365.25).cos().alias("an_cos"),
)
)Deux décisions structurent ensuite le travail. Stratégie d'horizon : la prévision récursive réinjecte ses propres prédictions pour avancer pas à pas (simple, mais les erreurs s'accumulent) ; la prévision directe entraîne un modèle par horizon (plus coûteux, plus stable au-delà de quelques pas). Validation : uniquement en avançant dans le temps, avec une fenêtre glissante ou extensible, et en respectant un écart égal à l'horizon entre entraînement et test — sans quoi on évalue une situation impossible en production.
shift(1) inclut la valeur courante : le modèle « prédit » en lisant sa propre cible, et le score est spectaculaire jusqu'à la mise en production. Le second piège est la disponibilité : une variable peut être passée mais ne pas être encore connue au moment où la prévision doit être produite — un chiffre consolidé publié avec trois jours de retard. Toujours raisonner en « que sais-je à l'instant où je prédis ? », pas en « quelle est la date de cette ligne ? ».
6. Deep learning et modèles de fondation
- N-BEATS / N-HiTS — empilements de blocs résiduels, sans composante récurrente ; performances solides et entraînement rapide.
- DeepAR — modèle autorégressif probabiliste entraîné sur un ensemble de séries apparentées : il apprend des motifs partagés, ce qui aide beaucoup les séries courtes.
- Temporal Fusion Transformer — attention sur les séquences (module 16) avec gestion propre des covariables connues à l'avance (calendrier, promotions) et une part d'interprétabilité.
- Modèles de fondation (Chronos, TimesFM, Moirai, TimeGPT) — pré-entraînés sur d'énormes corpus de séries, utilisables en zero-shot. Intéressants pour obtenir une baseline sans entraînement ; pas systématiquement meilleurs qu'un bon modèle spécifique, et à manier avec précaution quand la série contient de l'information confidentielle (module 27).
La bibliothèque nixtla (statsforecast / mlforecast / neuralforecast) donne accès aux trois familles avec la même interface, ce qui permet de les comparer honnêtement — la seule façon de trancher.
7. Prévision probabiliste et évaluation
Une prévision ponctuelle est rarement suffisante : dimensionner un stock ou une réserve d'énergie demande un quantile, pas une moyenne (module 24). On entraîne donc directement sur la perte pinball, qui pénalise asymétriquement selon le quantile visé :
Pour \(\tau = 0{,}9\), sous-estimer coûte neuf fois plus cher que surestimer : le modèle apprend donc à viser haut, et sa prédiction converge vers le quantile 90 %.
MAE / RMSE interprétables, mais non comparables entre séries d'échelles différentes
MAPE en pourcentage ; explose si y proche de 0 et pénalise asymétriquement
(surestimer de 100 % est borné, sous-estimer ne l'est pas)
sMAPE version symétrique, un peu moins instable
MASE erreur rapportée à celle de la prévision NAÏVE : < 1 = mieux que naïf.
LA métrique à préférer pour comparer des séries hétérogènes.
Pinball évalue un quantile donné
CRPS évalue toute la distribution prédictive ; se réduit à la MAE pour une
prévision ponctuelle. La référence en prévision probabiliste.Et la règle d'or : toujours comparer à la prévision naïve — la dernière valeur, ou la valeur de la même période l'an dernier. Un modèle qui ne bat pas la naïve saisonnière ne sert à rien, et c'est plus fréquent qu'on ne le croit.
8. Espace d'états et filtre de Kalman
Un modèle espace-état sépare ce qu'on cherche à connaître — un état caché \(x_t\) qui évolue selon une dynamique — de ce qu'on observe — \(z_t\), bruité et parfois indirect :
Le filtre de Kalman alterne deux étapes à chaque instant :
PRÉDICTION x̂ = F·x̂ "d'après mon modèle de dynamique, voilà où je devrais être"
P = F·P·Fᵀ + Q l'incertitude AUGMENTE (le modèle n'est pas parfait)
CORRECTION K = P·Hᵀ(H·P·Hᵀ + R)⁻¹ le GAIN : combien croire la mesure ?
x̂ = x̂ + K(z - H·x̂) on corrige avec l'écart à la mesure
P = (I - K·H)·P l'incertitude DIMINUE
Si R est grand (capteur bruité) → K petit → on fait confiance au modèle
Si Q est grand (modèle grossier) → K grand → on fait confiance à la mesureC'est l'estimateur optimal au sens de la variance minimale dans le cas linéaire-gaussien, et il est récursif : coût constant par pas, mémoire constante, quelle que soit la longueur de l'historique. D'où son omniprésence en navigation, en poursuite de cible et en fusion de capteurs. Les extensions traitent le cas non linéaire : EKF (linéarisation locale), UKF (propagation de points sigma, plus stable), et filtres particulaires (Monte-Carlo séquentiel, sans hypothèse gaussienne).
Pour un ingénieur, l'intérêt est double : lisser un signal bruité en temps réel, et estimer des grandeurs non mesurables directement à partir de mesures indirectes — ce qui relie ce module à l'assimilation de données du module 21.
9. Ruptures et anomalies
- Détection de rupture — identifier les dates où le régime change (changement de moyenne, de variance, de tendance). La bibliothèque
rupturesimplémente PELT et la segmentation binaire ; CUSUM reste la méthode de référence pour une surveillance en ligne. Usage concret : savoir à partir de quand les données sont encore représentatives, donc à partir de quand réentraîner (module 26). - Anomalies ponctuelles — un point s'écarte fortement de la prévision : on compare le résidu à un intervalle de prédiction plutôt qu'à un seuil fixe, ce qui rend la détection insensible à la saisonnalité (un pic le samedi n'est pas une anomalie si tous les samedis font un pic).
- Anomalies collectives — un motif anormal sur une fenêtre, détectable par distance entre sous-séquences (matrix profile) ou par erreur de reconstruction d'un autoencodeur (module 16).
- Un rappel utile — sur un flux, tester en continu revient à faire des milliers de tests : sans contrôle du taux de fausses alertes (module 9), le système d'alerte devient du bruit et finit ignoré.
10. Analyse spectrale et filtrage
Sur un signal physique — vibration, acoustique, mesure de capteur —, le domaine fréquentiel révèle souvent ce que le domaine temporel cache. La FFT donne le périodogramme, la méthode de Welch le lisse en moyennant des segments (ce qui réduit la variance de l'estimation au prix de la résolution), et la densité spectrale de puissance identifie les composantes périodiques : une fréquence de rotation, une résonance, un harmonique de défaut de roulement.
import numpy as np
from scipy import signal
f, Pxx = signal.welch(x, fs=25_600, nperseg=4096) # densité spectrale de puissance
pic = f[np.argmax(Pxx)]
print(f"fréquence dominante : {pic:.1f} Hz")
# spectrogramme : évolution du contenu fréquentiel DANS LE TEMPS
f, t, Sxx = signal.spectrogram(x, fs=25_600, nperseg=1024)
# filtrage passe-bande SANS déphasage (filtrage aller-retour)
sos = signal.butter(4, [50, 2000], btype="band", fs=25_600, output="sos")
x_filtre = signal.sosfiltfilt(sos, x) # filtfilt : phase nulle, ordre doubléDeux usages en machine learning. D'abord, le spectre fournit d'excellentes variables : énergie par bande, fréquence dominante, kurtosis spectral, coefficients cepstraux — c'est la base de la maintenance prédictive sur signaux vibratoires. Ensuite, le spectrogramme transforme un signal unidimensionnel en image bidimensionnelle, ce qui permet d'appliquer directement un CNN (modules 16 et 18) — l'approche standard en classification audio.
Deux pièges classiques du traitement du signal restent valables ici : le repliement de spectre (respecter Shannon, filtrer avant d'échantillonner, sinon les hautes fréquences se déguisent en basses) et les fuites spectrales (utiliser une fenêtre de Hann plutôt qu'une troncature brutale, qui introduit des discontinuités artificielles). Et pour les phénomènes non stationnaires, la transformée en ondelettes offre un meilleur compromis temps-fréquence que la FFT à fenêtre.
11. Durées de vie, censure et fiabilité
Troisième famille temporelle, et la plus mal traitée en pratique : on veut prédire le temps avant un événement — panne d'un composant, résiliation d'un client, rechute d'un patient. La difficulté s'appelle la censure : à la fin de l'étude, beaucoup d'unités n'ont pas encore connu l'événement.
unité 1 ├──────────✕ ✕ = panne observée (durée connue : 8 mois)
unité 2 ├───────────────────────→ → = toujours en service à la fin
unité 3 ├────✕ (durée INCONNUE, mais ≥ 14 mois)
unité 4 ├──────────────────→
└──────────────────────────► temps
Les EXCLURE → on ne garde que les pannes précoces → durée de vie SOUS-ESTIMÉE
Les compter → on suppose qu'elles tombent en panne à la date de fin d'étude
comme pannes → encore sous-estimée
→ il faut une méthode qui utilise l'information "a survécu AU MOINS 14 mois"Deux fonctions suffisent à tout exprimer — la survie et le taux de défaillance instantané :
\(h(t)\) se lit « sachant que l'unité a tenu jusqu'à \(t\), quel est son risque de tomber maintenant ? » — c'est la quantité qui intéresse un ingénieur fiabiliste, et elle est directement reliée à la survie par l'exponentielle de son intégrale.
Kaplan-Meier estimation non paramétrique de S(t), gérant la censure.
Le point de départ, toujours.
Test du log-rank comparer deux courbes de survie (deux lots, deux traitements).
Cox (PH) h(t|x) = h₀(t)·exp(βᵀx) : les covariables agissent de façon
MULTIPLICATIVE sur le risque, sans qu'on spécifie h₀.
exp(β) se lit comme un rapport de risques.
Hypothèse à vérifier : risques proportionnels (résidus de Schoenfeld).
Weibull / AFT modèle paramétrique : les covariables ACCÉLÈRENT le temps.
Permet d'EXTRAPOLER au-delà de la fenêtre d'observation,
ce que Cox ne fait pas.
Survie par ML Random Survival Forest, gradient boosting de Cox, DeepSurv :
capturent non-linéarités et interactions.Le paramètre de forme de la loi de Weibull se lit directement comme un diagnostic de mode de défaillance : \(k \lt 1\) correspond à un taux décroissant (mortalité infantile, défauts de fabrication), \(k = 1\) à un taux constant (défaillances aléatoires, loi exponentielle sans mémoire), \(k \gt 1\) à un taux croissant (usure). C'est la lecture de la courbe en baignoire de la fiabilité, et c'est ce qui permet de distinguer un problème de qualité d'un problème de vieillissement — deux situations qui appellent des actions opposées.
from lifelines import KaplanMeierFitter, CoxPHFitter, WeibullFitter
from lifelines.statistics import logrank_test
# evenement = 1 si la panne a été observée, 0 si l'unité était encore en service
km = KaplanMeierFitter().fit(durees, evenement_observe)
km.plot_survival_function()
print("durée médiane de survie :", km.median_survival_time_)
# comparer deux lots
print(logrank_test(d_lotA, d_lotB, e_lotA, e_lotB).p_value)
cox = CoxPHFitter().fit(df, duration_col="duree", event_col="panne")
cox.print_summary() # rapports de risques et intervalles
cox.check_assumptions(df) # test des risques proportionnels
wb = WeibullFitter().fit(durees, evenement_observe)
print(f"paramètre de forme ρ = {wb.rho_:.2f}") # < 1 rodage, ≈ 1 aléatoire, > 1 usureLe lien avec la maintenance prédictive
Prédire la durée de vie résiduelle (RUL) d'un équipement combine tout ce module : variables spectrales issues des capteurs (section 10), modèle de dégradation en espace d'états (section 8), et modèle de survie pour la probabilité de défaillance à un horizon donné (section 11). Deux exigences industrielles s'ajoutent : une prédiction probabiliste, parce qu'une décision de remplacement se prend sur un quantile bas et non sur une espérance (module 24), et une anticipation suffisante — un modèle qui prédit la panne deux heures avant est exact et inutile. La métrique doit donc incorporer le coût asymétrique entre une intervention inutile et une défaillance subie.
Ce qu'il faut retenir du module
- L'autocorrélation réduit l'information effective : les tests et la validation doivent en tenir compte.
- Décomposer et stationnariser avant de modéliser ; ACF et PACF restent les graphiques les plus instructifs.
- ETS et ARIMA battent souvent le ML sur peu de séries courtes ; le ML gagne sur beaucoup de séries avec covariables.
- Toute variable doit être strictement passée et réellement disponible au moment de la prévision.
- Comparer systématiquement à la prévision naïve, et préférer MASE et CRPS.
- Kalman estime un état caché en temps réel, avec un coût constant par pas ; le gain arbitre entre modèle et mesure.
- La censure ne s'ignore pas : Kaplan-Meier, Cox et Weibull existent pour ça, et le paramètre de forme de Weibull diagnostique le mode de défaillance.