IoT et IA

Détection de valeurs aberrantes dans les données de capteurs avec Z-score, IQR et EWMA

Trois méthodes simples et explicables pour repérer les valeurs aberrantes dans les flux de capteurs, avec des implémentations Python à exécuter sur un flux de température MQTT en direct et des conseils sur les cas où chacune échoue.

Graphique de détection de valeurs aberrantes de capteurs comparant les bandes Z-score, IQR et EWMA sur un flux de température avec les valeurs aberrantes signalées
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

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 :

  1. Nettoyer. Supprimer ou signaler les pics et les valeurs impossibles avant qu'ils n'atteignent tableaux de bord, moyennes et modèles.
  2. 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

  1. 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).
  2. Détectez séparément les valeurs bloquées en vérifiant si les mesures restent identiques sur une période donnée.
  3. Choisissez des tailles de fenêtre en durée, et non en nombre d'échantillons, si les intervalles de publication varient.
  4. Fixez des largeurs de bande minimales égales à la résolution du capteur.
  5. Signalez les valeurs aberrantes au lieu de les supprimer, et conservez la valeur brute pour une analyse ultérieure.
  6. Exigez deux ou trois signalements consécutifs avant d'alerter une personne.
  7. 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.

Articles liés

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.