La détection de valeurs aberrantes de capteurs n'a pas besoin de machine learning pour être utile. Trois techniques classiques, le Z-score, l'écart interquartile (IQR) et la moyenne mobile à pondération exponentielle (EWMA), repèrent la plupart des pics, des pertes de signal et des dérives dans les flux de température. Cet article explique le fonctionnement de chacune, ses points faibles, et fournit du code Python qui applique les trois à un flux MQTT en direct.
Valeurs aberrantes et anomalies dans les flux de capteurs
Une valeur aberrante est une mesure très éloignée des autres. Une anomalie est une mesure ou un motif indiquant que quelque chose d'inhabituel se produit dans le monde réel. Les deux se recoupent sans être identiques. Une mesure isolée extravagante due à un parasite électrique est une valeur aberrante, pas une anomalie de procédé ; une lente hausse de deux degrés en une heure peut ne jamais produire de valeur aberrante tout en signalant un ventilateur de refroidissement défaillant.
La détection de valeurs aberrantes de capteurs a donc deux missions :
- Nettoyer. Supprimer ou signaler les pics et les valeurs impossibles avant qu'ils n'atteignent tableaux de bord, moyennes et modèles.
- Alerter tôt. Mettre en évidence les mesures qui méritent attention parce qu'elles rompent avec le motif récent.
Les méthodes ci-dessous assurent ces deux missions, avec des forces différentes. Pour l'architecture d'ensemble, détecteurs de machine learning compris, consultez les méthodes de détection d'anomalies IoT.
Z-score : la distance en écarts-types
Le Z-score mesure à combien d'écarts-types une valeur se trouve de la moyenne :
z = (x - mean) / std
Une mesure dont le Z-score dépasse 3 en valeur absolue est une règle courante de valeur aberrante. En streaming, on calcule la moyenne et l'écart-type sur une fenêtre glissante de mesures récentes plutôt que sur tout l'historique, afin que la référence suive les évolutions lentes.
Points forts : facile à expliquer, rapide, efficace lorsque le signal suit à peu près une loi normale autour d'un niveau stable.
Points faibles : la moyenne et l'écart-type sont eux-mêmes faussés par les valeurs aberrantes. Une rafale de pics gonfle l'écart-type et masque le pic suivant. La méthode suppose aussi un bruit symétrique, ce qui n'est pas le cas de nombreux capteurs.
Une variante robuste remplace la moyenne par la médiane et l'écart-type par l'écart absolu médian (MAD). C'est cette version qu'utilise le tutoriel détection d'anomalies en temps réel en Python.
IQR : les bornes interquartiles
L'écart interquartile utilise des percentiles plutôt que des moyennes :
Q1 = 25th percentile, Q3 = 75th percentile, IQR = Q3 - Q1
lower fence = Q1 - 1.5 * IQR
upper fence = Q3 + 1.5 * IQR
Toute valeur en dehors des bornes est une valeur aberrante. Utilisez 3 au lieu de 1,5 pour les valeurs aberrantes « extrêmes ».
Points forts : robuste aux valeurs aberrantes qu'il recherche, aucune hypothèse de normalité, gère les données asymétriques comme les amplitudes de vibration ou le courant consommé.
Points faibles : nécessite une fenêtre assez grande pour obtenir des quartiles stables, et sur des capteurs fortement quantifiés (un capteur de température d'une résolution de 0,5 degré, par exemple), l'IQR peut tomber à zéro et signaler la moindre variation. Ajoutez une largeur de borne minimale égale à la résolution du capteur.
EWMA : une référence lissée avec des limites de contrôle
L'EWMA tient à jour une valeur lissée dans laquelle les mesures récentes pèsent davantage :
ewma = alpha * x + (1 - alpha) * ewma_previous
En parallèle, vous suivez une variance à pondération exponentielle et signalez les mesures situées en dehors de ewma ± k * ewm_std. Un petit alpha (0,01 à 0,05) donne une référence lente et stable ; un alpha plus grand suit rapidement les changements.
Points forts : mémoire constante (deux nombres par signal), idéale pour les microcontrôleurs, s'adapte naturellement aux dérives lentes et sensible aux petits décalages durables lorsqu'elle est utilisée comme carte de contrôle.
Points faibles : comme elle s'adapte, un défaut lent peut être absorbé dans la référence. Associez-la à une limite absolue pour les valeurs qui ne doivent jamais être dépassées.
Comparaison des méthodes
| Méthode | Mémoire par signal | Robuste aux valeurs aberrantes | Gère l'asymétrie | Détecte les dérives lentes | Tient sur un microcontrôleur |
|---|---|---|---|---|---|
| Z-score glissant | Fenêtre de N valeurs | Non | Non | Mal | Oui, avec un petit N |
| Z robuste (médiane/MAD) | Fenêtre de N valeurs | Oui | En partie | Mal | Oui, avec un petit N |
| Bornes IQR | Fenêtre de N valeurs | Oui | Oui | Mal | Oui, avec un petit N |
| Limites de contrôle EWMA | Deux nombres | En partie | Non | Oui, avec un petit alpha | Facilement |
Aucune méthode ne l'emporte seule. Une combinaison pratique pour la température : des limites physiques strictes, l'IQR pour les pics et l'EWMA avec un petit alpha pour la dérive.
Détection de valeurs aberrantes de capteurs en Python
Le code ci-dessous implémente les trois détecteurs sous forme de petites classes dotées d'une méthode update, afin de pouvoir les exécuter côte à côte sur le même flux.
# detectors.py
import math
import statistics
from collections import deque
class RollingZ:
def __init__(self, window=60, k=3.0):
self.buf, self.k = deque(maxlen=window), k
def update(self, x):
flagged = False
if len(self.buf) >= 20:
mean = statistics.fmean(self.buf)
std = statistics.pstdev(self.buf) or 1e-9
flagged = abs(x - mean) / std > self.k
if not flagged:
self.buf.append(x)
return flagged
class IQRFence:
def __init__(self, window=60, k=1.5, min_width=0.2):
self.buf, self.k, self.min_width = deque(maxlen=window), k, min_width
def update(self, x):
flagged = False
if len(self.buf) >= 20:
q1, _, q3 = statistics.quantiles(self.buf, n=4)
iqr = max(q3 - q1, self.min_width)
flagged = x < q1 - self.k * iqr or x > q3 + self.k * iqr
if not flagged:
self.buf.append(x)
return flagged
class EWMA:
def __init__(self, alpha=0.05, k=4.0, warmup=20):
self.alpha, self.k, self.warmup = alpha, k, warmup
self.mean, self.var, self.n = None, 0.0, 0
def update(self, x):
self.n += 1
if self.mean is None:
self.mean = x
return False
diff = x - self.mean
std = math.sqrt(self.var) or 1e-9
flagged = self.n > self.warmup and abs(diff) > self.k * std
if not flagged:
self.mean += self.alpha * diff
self.var = (1 - self.alpha) * (self.var + self.alpha * diff * diff)
return flagged
Chaque détecteur ignore, pour son apprentissage, les valeurs qu'il signale, ce qui empêche un pic de contaminer la référence.
Application à un flux de température MQTT en direct
Pour tester de bout en bout, publiez des températures simulées sur le serveur MQTT public gratuit broker.connectmq.com et exécutez les détecteurs dans un abonné. Remplacez t9x4q2 par votre propre identifiant aléatoire ; l'espace public est lisible par tous, n'utilisez donc que des données synthétiques.
# temp_sim.py
import json, random, time, uuid
import paho.mqtt.client as mqtt
TOPIC = "connectmq/demo/t9x4q2/lab/room1/temperature"
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"tsim-{uuid.uuid4().hex[:6]}")
c.connect("broker.connectmq.com", 1883, keepalive=60)
c.loop_start()
base = 21.0
while True:
base += random.gauss(0, 0.01) # variation lente
value = base + random.gauss(0, 0.15)
if random.random() < 0.02:
value += random.choice([-6, 7]) # pic occasionnel
c.publish(TOPIC, json.dumps({"tempC": round(value, 2), "ts": time.time()}))
time.sleep(1)
# temp_outliers.py
import json, uuid
import paho.mqtt.client as mqtt
from detectors import RollingZ, IQRFence, EWMA
TOPIC = "connectmq/demo/t9x4q2/lab/room1/temperature"
detectors = {"z": RollingZ(), "iqr": IQRFence(), "ewma": EWMA()}
def on_connect(client, userdata, flags, reason_code, properties):
client.subscribe(TOPIC)
def on_message(client, userdata, msg):
x = json.loads(msg.payload)["tempC"]
flags = {name: d.update(x) for name, d in detectors.items()}
if any(flags.values()):
print(f"{x:6.2f} flagged by: {[n for n, f in flags.items() if f]}")
client.publish(TOPIC.rsplit("/", 1)[0] + "/outliers",
json.dumps({"tempC": x, "flags": flags}), qos=1)
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=f"tout-{uuid.uuid4().hex[:6]}")
c.on_connect = on_connect
c.on_message = on_message
c.connect("broker.connectmq.com", 1883, keepalive=60)
c.loop_forever()
Lancez les deux scripts et observez quels détecteurs sont d'accord. En général, les trois repèrent les grands pics, tandis que le Z-score manque parfois un pic qui suit de près un autre, exactement la faiblesse décrite plus haut.
Détecter sur l'équipement ou après le broker
Vous pouvez exécuter ces détecteurs à deux endroits, et ce choix influe sur ce que vous publiez.
Les exécuter sur le nœud capteur, par exemple un ESP32, permet à l'équipement d'ajouter un indicateur de valeur aberrante à chaque message ou de ne publier que lorsqu'il se passe quelque chose d'intéressant. Cela économise de la bande passante et fonctionne même quand le réseau est coupé, mais les seuils sont figés dans le firmware et plus difficiles à modifier.
Les exécuter après le broker, dans un abonné comme celui ci-dessus, garde les équipements simples et vous permet de changer de méthode et de seuils à tout moment, de comparer plusieurs détecteurs en parallèle et de retraiter l'historique. La contrepartie est que chaque mesure brute doit transiter jusqu'au broker.
Un compromis courant consiste à placer une limite stricte et un contrôle de valeur bloquée sur l'équipement, ce qui détecte immédiatement les capteurs défectueux, et les détecteurs statistiques dans un service abonné où ils sont faciles à régler. Avec un broker ConnectMQ au milieu, les deux sorties aboutissent sur des topics que les mêmes tableaux de bord peuvent lire.
Liste de contrôle pratique
- Appliquez d'abord des limites physiques strictes (un capteur de pièce qui indique 150 degrés est en défaut, ce n'est pas une valeur aberrante).
- Détectez séparément les valeurs bloquées en vérifiant si les mesures restent identiques sur une période donnée.
- Choisissez des tailles de fenêtre en durée, et non en nombre d'échantillons, si les intervalles de publication varient.
- Fixez des largeurs de bande minimales égales à la résolution du capteur.
- Signalez les valeurs aberrantes au lieu de les supprimer, et conservez la valeur brute pour une analyse ultérieure.
- Exigez deux ou trois signalements consécutifs avant d'alerter une personne.
- Revoyez les seuils après une semaine de données réelles.
Lorsque les signaux interagissent, par exemple le courant et le débit d'une pompe, ces méthodes par signal atteignent leurs limites, et un modèle multivarié comme Isolation Forest sur des données de capteurs devient intéressant.
La place du broker
Chacun des éléments ci-dessus est un client MQTT ordinaire : le capteur publie, le détecteur s'abonne et republie. Le broker MQTT se contente de router les messages, ce qui signifie que vous pouvez ajouter, retirer ou remplacer des détecteurs sans toucher aux équipements. Pour les déploiements réels, un broker MQTT privé dans le cloud comme ConnectMQ ajoute TLS, identifiants et un explorateur de topics en direct où vous pouvez suivre côte à côte les mesures brutes et les valeurs aberrantes signalées. Pour d'autres façons d'associer analytique et équipements, consultez le guide IA et IoT.
Démarrer avec ConnectMQ
Créez un broker MQTT managé avec l'offre gratuite Serverless sur app.connectmq.com, sans carte bancaire, connectez-y vos capteurs et exécutez le détecteur de valeurs aberrantes sur vos propres données plutôt que sur le simulateur.
Questions fréquentes
Quelle méthode de détection de valeurs aberrantes est la meilleure pour les capteurs de température ?
Une combinaison fonctionne le mieux : limites physiques, bornes IQR pour les pics et EWMA avec un petit facteur de lissage pour les dérives lentes. La température évolue lentement, ce qui rend l'EWMA particulièrement efficace.
Quelle taille de fenêtre utiliser pour les statistiques glissantes ?
Couvrez assez de temps pour capturer le bruit normal, mais pas au point que les changements légitimes mettent une éternité à être absorbés. Pour une mesure par seconde, une à cinq minutes est un point de départ raisonnable.
Faut-il supprimer les valeurs aberrantes des données ?
Signalez-les plutôt que de les supprimer. Conservez la valeur brute avec un indicateur de valeur aberrante pour pouvoir auditer les décisions et réentraîner les modèles plus tard.
Ces méthodes peuvent-elles s'exécuter sur un ESP32 ?
Oui. L'EWMA ne nécessite que deux flottants par signal, et une fenêtre glissante de 30 à 60 valeurs tient facilement dans la mémoire d'un ESP32 : vous pouvez donc signaler les valeurs aberrantes avant la publication.



