Une moyenne où le passé récent pèse plus que le passé lointain, avec des poids qui décroissent de façon exponentielle. Un seul paramètre, alpha, règle la réactivité. Rapide, robuste, sans hypothèse compliquée : c'est la base de nombreux outils de prévision et de surveillance en continu.
Un thermostat qui ne réagit pas à chaque courant d'air, mais suit la température de la pièce. Chaque nouvelle mesure le fait bouger un peu, jamais d'un coup.
Au départ, le niveau est la première mesure.
À chaque nouvelle mesure : nouveau niveau = ancien niveau + alpha × (mesure - ancien niveau). Avec alpha = 0,05, le niveau ne bouge que de 5 % de l'écart.
La prévision du point suivant est le dernier niveau calculé. Elle est plate : le lissage simple ne prévoit ni tendance ni saison.
Une mesure par heure, très bruitée autour d'un niveau stable. À partir du 28 février, une usure fait dériver lentement le niveau, jusqu'à la panne.
alpha est estimé à 0,05 sur le jeu d'exemple. Le niveau lissé prévoit l'heure suivante avec une erreur de 0,31 contre 0,42 en reprenant la dernière mesure. Un seuil à 3 écarts-types sur le niveau lissé ne donne aucune fausse alerte avant la dérive, contre 2 sur la mesure brute, et détecte la dérive plus de deux semaines avant la période de panne.
Pour une alerte, on mesure deux choses sur l'historique : combien de fausses alertes en fonctionnement normal, et combien de temps après le début d'un problème on le détecte. Alpha arbitre entre les deux.
Noms donnés pour R (HoltWinters, ou ses dans le package forecast) et Python (pandas ewm, ou SimpleExpSmoothing dans statsmodels).
Entre 0 et 1. Proche de 1, le niveau suit la dernière mesure et garde tout le bruit. Proche de 0, il est très lisse mais réagit lentement. On l'estime en minimisant l'erreur de prévision passée, puis on vérifie qu'il est cohérent avec le métier.
Le point de départ du lissage. Il ne compte que sur les premières périodes : on écarte ces périodes de rodage des calculs de seuil, comme les 24 premières heures dans l'exemple.
Calé sur une période jugée normale, sur la série lissée elle-même : elle varie beaucoup moins que la mesure brute. Trois écarts-types est un point de départ, à ajuster selon le coût d'une fausse alerte.
# Surveillance machine : lissage exponentiel simple en R
capteurs <- read.csv("capteurs_machine.csv")
vib <- capteurs$vibration
# HoltWinters sans tendance ni saison = lissage exponentiel simple
# alpha est choisi pour minimiser l'erreur de prévision à 1 heure
modele <- HoltWinters(ts(vib), beta = FALSE, gamma = FALSE)
alpha <- unname(modele$alpha)
cat("alpha :", round(alpha, 3), "\n")
# Niveau lissé : niveau = alpha x mesure + (1 - alpha) x niveau précédent
niveau <- as.numeric(stats::filter(alpha * vib, 1 - alpha, method = "recursive", init = vib[1]))
# Seuil d'alerte calé sur une période normale (heures 25 à 1000) ; dérive à partir de la ligne 1401
for (nom in c("lissé", "brut")) {
serie <- if (nom == "lissé") niveau else vib
seuil <- mean(serie[25:1000]) + 3 * sd(serie[25:1000])
alertes <- which(serie > seuil & seq_along(serie) > 24)
cat(nom, "| seuil :", round(seuil, 2), "| alertes avant la dérive :", sum(alertes < 1401),
"| première après :", capteurs$horodatage[alertes[alertes >= 1401][1]], "\n")
}
cat("Prévision pour la prochaine heure :", round(niveau[length(niveau)], 2), "\n")
# Surveillance machine : lissage exponentiel simple en Python
import numpy as np
import pandas as pd
capteurs = pd.read_csv("capteurs_machine.csv", parse_dates=["horodatage"], index_col="horodatage")
vib = capteurs["vibration"]
# Niveau lissé : niveau = alpha x mesure + (1 - alpha) x niveau précédent
def erreur(alpha):
niveau = vib.ewm(alpha=alpha, adjust=False).mean()
return np.sqrt(np.mean((vib.values[1:] - niveau.values[:-1]) ** 2)) # erreur à 1 heure
# Alpha choisi pour minimiser l'erreur de prévision à 1 heure
grille = np.round(np.arange(0.01, 1.0, 0.01), 2)
alpha = grille[np.argmin([erreur(a) for a in grille])]
print("alpha :", alpha, "| erreur lissage :", round(erreur(alpha), 3), "| erreur dernière mesure :", round(erreur(1.0), 3))
# Seuil d'alerte calé sur une période normale (heures 24 à 1000)
niveau = vib.ewm(alpha=alpha, adjust=False).mean()
debut = pd.Timestamp("2025-02-28 08:00") # début de la dérive, connu après coup
seuils = {"lissé": (niveau, niveau.iloc[24:1000]), "brut": (vib, vib.iloc[24:1000])}
for nom, (serie, normal) in seuils.items():
seuil = normal.mean() + 3 * normal.std()
alertes = serie.iloc[24:][serie.iloc[24:] > seuil].index
print(nom, "| seuil :", round(seuil, 2), "| alertes avant la dérive :", (alertes < debut).sum(),
"| première après :", alertes[alertes >= debut][0])
print("Prévision pour la prochaine heure :", round(niveau.iloc[-1], 2))
On le fait estimer par l'outil, qui cherche la valeur minimisant l'erreur de prévision sur l'historique. Une valeur autour de 0,1 à 0,3 est courante pour des ventes. Un alpha très proche de 1 signale souvent une tendance ou une rupture que le lissage simple ne sait pas suivre.
Le niveau est une moyenne de toutes les mesures passées, avec des poids qui diminuent d'un facteur (1 - alpha) à chaque période. Ces poids suivent une décroissance exponentielle : avec alpha = 0,05, une mesure vieille de 14 heures pèse environ deux fois moins que la dernière.
Le simple suit un niveau. Le double, ou méthode de Holt, ajoute une tendance. Le triple, ou Holt-Winters, ajoute une saisonnalité. On choisit selon ce que montre la série.
Même idée, mais les k dernières mesures comptent autant et les plus anciennes plus du tout.
Voir la fiche → avec tendance et saisonAjoute au niveau une tendance et un profil saisonnier, chacun avec son propre lissage.
Voir la fiche → la version généraleLe lissage simple en est un cas particulier. Kalman gère plusieurs mesures, plusieurs états cachés et un gain qui s'adapte.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus