IoT ve Yapay Zekâ

Z-Skoru, IQR ve EWMA ile Sensör Verisinde Aykırı Değer Tespiti

Sensör akışlarında aykırı değerleri bulmak için üç basit ve açıklanabilir yöntem; canlı bir MQTT sıcaklık akışında çalıştırabileceğiniz Python uygulamaları ve her birinin ne zaman başarısız olduğuna dair yol gösterici bilgiler.

Bir sıcaklık akışında Z-skoru, IQR ve EWMA bantlarını işaretlenmiş aykırı değerlerle karşılaştıran sensör verisinde aykırı değer tespiti grafiği
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

Sensör verisinde aykırı değer tespitinin faydalı olması için makine öğrenmesi gerekmez. Üç klasik teknik, yani Z-skoru, çeyrekler açıklığı (IQR) ve üstel ağırlıklı hareketli ortalama (EWMA), sıcaklık akışlarındaki sıçramaların, kesintilerin ve kaymaların çoğunu yakalar. Bu makale her birinin nasıl çalıştığını ve nerede bozulduğunu açıklıyor ve üçünü de canlı bir MQTT akışına uygulayan Python kodu sunuyor.

Sensör Akışlarında Aykırı Değer ile Anomali Arasındaki Fark

Aykırı değer, diğerlerinden çok uzakta duran bir okumadır. Anomali ise gerçek dünyada olağandışı bir şey olduğuna işaret eden bir okuma veya örüntüdür. İkisi örtüşür ama aynı değildir. Elektriksel gürültüden kaynaklanan tek bir uçuk okuma bir aykırı değerdir ama bir proses anomalisi değildir; bir saat içinde yavaşça gerçekleşen iki derecelik bir artış ise hiçbir zaman aykırı değer üretmeyebilir, yine de arızalanmakta olan bir soğutma fanına işaret edebilir.

Bu yüzden sensör verisinde aykırı değer tespitinin iki görevi vardır:

  1. Temizleme. Sıçramaları ve imkânsız değerleri dashboard'lara, ortalamalara ve modellere ulaşmadan önce kaldırmak veya işaretlemek.
  2. Erken uyarı. Son örüntüyü bozdukları için dikkat gerektiren okumaları öne çıkarmak.

Aşağıdaki yöntemler her ikisini de farklı güçlü yönlerle ele alır. Makine öğrenmesi dedektörleri dahil daha geniş mimari için IoT anomali tespiti yöntemleri yazısına bakın.

Z-Skoru: Standart Sapma Cinsinden Uzaklık

Z-skoru, bir değerin ortalamadan kaç standart sapma uzakta olduğunu ölçer:

z = (x - mean) / std

Mutlak Z-skoru 3'ün üzerinde olan bir okuma, yaygın bir aykırı değer kuralıdır. Akış bağlamında ortalama ve standart sapmayı tüm geçmiş yerine son okumalardan oluşan kayan bir pencere üzerinde hesaplarsınız; böylece referans yavaş değişimleri takip eder.

Güçlü yönleri: açıklaması kolay, hızlı, sinyal kararlı bir seviye etrafında kabaca normal dağıldığında iyi çalışır.

Zayıf yönleri: ortalama ve standart sapmanın kendisi aykırı değerler tarafından bozulur. Bir sıçrama patlaması standart sapmayı şişirir ve bir sonraki sıçramayı gizler. Ayrıca birçok sensörde bulunmayan simetrik bir gürültü varsayar.

Sağlam (robust) bir varyant, ortalamanın yerine medyanı, standart sapmanın yerine ise medyan mutlak sapmayı (MAD) koyar. Bu sürüm Python ile gerçek zamanlı anomali tespiti eğitiminde kullanılıyor.

IQR: Çeyrek Sınırları

Çeyrekler açıklığı, ortalamalar yerine yüzdelikleri kullanır:

Q1 = 25th percentile, Q3 = 75th percentile, IQR = Q3 - Q1
lower fence = Q1 - 1.5 * IQR
upper fence = Q3 + 1.5 * IQR

Sınırların dışındaki her şey aykırı değerdir. "Uç" aykırı değerler için 1,5 yerine 3 kullanın.

Güçlü yönleri: aradığı aykırı değerlere karşı dayanıklıdır, normallik varsayımı yoktur, titreşim genlikleri veya akım çekişi gibi çarpık verileri ele alır.

Zayıf yönleri: kararlı çeyrekler için yeterince büyük bir pencere gerektirir ve yüksek oranda kuantize sensörlerde (örneğin 0,5 derece çözünürlüklü bir sıcaklık sensörü) IQR sıfıra çökebilir ve her küçük değişikliği işaretleyebilir. Sensörün çözünürlüğüne eşit bir minimum sınır genişliği ekleyin.

EWMA: Kontrol Limitli Yumuşatılmış Referans

EWMA, son okumaların daha fazla ağırlık taşıdığı, sürekli güncellenen yumuşatılmış bir değer tutar:

ewma = alpha * x + (1 - alpha) * ewma_previous

Bunun yanında üstel ağırlıklı bir varyansı da izler ve ewma ± k * ewm_std dışına düşen okumaları işaretlersiniz. Küçük bir alpha (0,01 ila 0,05) yavaş ve kararlı bir referans verir; daha büyük bir alpha değişimleri hızla takip eder.

Güçlü yönleri: sabit bellek (sinyal başına iki sayı), mikrodenetleyiciler için ideal, yavaş kaymaya doğal olarak uyum sağlar ve kontrol grafiği olarak kullanıldığında küçük ama kalıcı kaymalara duyarlıdır.

Zayıf yönleri: uyum sağladığı için yavaş ilerleyen bir arıza referansın içine emilebilir. Asla aşılmaması gereken değerler için onu mutlak bir sınırla eşleştirin.

Yöntemlerin Karşılaştırması

Yöntem Sinyal başına bellek Aykırı değerlere dayanıklı Çarpıklığı ele alır Yavaş kaymayı tespit eder Mikrodenetleyiciye sığar
Kayan Z-skoru N değerlik pencere Hayır Hayır Zayıf Evet, küçük N ile
Sağlam Z (medyan/MAD) N değerlik pencere Evet Kısmen Zayıf Evet, küçük N ile
IQR sınırları N değerlik pencere Evet Evet Zayıf Evet, küçük N ile
EWMA kontrol limitleri İki sayı Kısmen Hayır Evet, küçük alpha ile Kolaylıkla

Tek bir yöntem her durumda kazanmaz. Sıcaklık için pratik bir kombinasyon şudur: katı fiziksel sınırlar, sıçramalar için IQR ve kayma için küçük alpha'lı EWMA.

Python ile Sensör Verisinde Aykırı Değer Tespiti

Aşağıdaki kod, üç dedektörü de update metoduna sahip küçük sınıflar olarak uygular; böylece onları aynı akış üzerinde yan yana çalıştırabilirsiniz.

# 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

Her dedektör işaretlediği değerlerden öğrenmeyi atlar; bu da bir sıçramanın referansı kirletmesini önler.

Canlı Bir MQTT Sıcaklık Akışına Uygulamak

Bunu uçtan uca denemek için simüle edilmiş sıcaklıkları broker.connectmq.com adresindeki genel MQTT test broker'ına yayınlayın ve dedektörleri bir abonede çalıştırın. t9x4q2 değerini kendi rastgele kimliğinizle değiştirin; genel alan herkes tarafından okunabilir, bu yüzden yalnızca sentetik veri kullanın.

# 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)                 # yavaş gezinme
    value = base + random.gauss(0, 0.15)
    if random.random() < 0.02:
        value += random.choice([-6, 7])           # ara sıra sıçrama
    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()

İkisini de çalıştırın ve hangi dedektörlerin hemfikir olduğunu izleyin. Genellikle üçünün de büyük sıçramaları yakaladığını, Z-skorunun ise bir başka sıçramanın hemen ardından gelen bir sıçramayı ara sıra kaçırdığını göreceksiniz; bu da tam olarak yukarıda açıklanan zayıflıktır.

Cihazda mı, Broker'dan Sonra mı Tespit

Bu dedektörleri iki yerde çalıştırabilirsiniz ve seçim, neyi yayınlayacağınızı etkiler.

Örneğin bir ESP32 gibi sensör düğümünde çalıştırmak, cihazın her mesaja bir aykırı değer işareti ekleyebilmesi veya yalnızca ilginç bir şey olduğunda yayın yapabilmesi anlamına gelir. Bu bant genişliğinden tasarruf sağlar ve ağ kesik olduğunda bile çalışır; ancak eşikler firmware'e gömülüdür ve değiştirilmeleri daha zordur.

Broker'dan sonra, yukarıdaki gibi bir abonede çalıştırmak ise cihazları basit tutar; yöntemleri ve eşikleri istediğiniz zaman değiştirmenize, birkaç dedektörü paralel olarak karşılaştırmanıza ve geçmişi yeniden işlemenize olanak tanır. Bedeli, her ham okumanın broker'a kadar taşınmasının gerekmesidir.

Yaygın bir orta yol, bozuk sensörleri anında yakalayan katı bir sınır ve takılı değer kontrolünü cihazda, ayarlaması kolay istatistiksel dedektörleri ise bir abone serviste çalıştırmaktır. Ortada bir ConnectMQ broker'ı olduğunda her iki çıktı da aynı dashboard'ların okuyabileceği topic'lere düşer.

Pratik Kontrol Listesi

  1. Önce katı fiziksel sınırları uygulayın (150 derece okuyan bir oda sensörü aykırı değer değil, arızadır).
  2. Belirli bir süre boyunca aynı okumaları kontrol ederek takılı değerleri ayrıca tespit edin.
  3. Yayın aralıkları değişkense pencere boyutlarını örnek sayısıyla değil, zamanla belirleyin.
  4. Minimum bant genişliklerini sensörün çözünürlüğüne göre ayarlayın.
  5. Aykırı değerleri silmek yerine işaretleyin ve ham değeri sonraki analizler için saklayın.
  6. Bir kişiyi uyarmadan önce iki veya üç ardışık işaret arayın.
  7. Bir haftalık gerçek veriden sonra eşikleri yeniden gözden geçirin.

Örneğin bir pompadaki akım ve debi gibi sinyaller birbirini etkilediğinde, bu sinyal başına yöntemler sınırlarına ulaşır ve sensör verisinde Isolation Forest gibi çok değişkenli bir model değerli hâle gelir.

Broker'ın Yeri

Yukarıdaki her parça sıradan bir MQTT client'ıdır: sensör yayın yapar, dedektör abone olur ve yeniden yayınlar. MQTT broker yalnızca mesajları yönlendirir; bu da cihazlara dokunmadan dedektör ekleyebileceğiniz, kaldırabileceğiniz veya değiştirebileceğiniz anlamına gelir. Gerçek kurulumlar için ConnectMQ gibi özel bir bulut MQTT broker, TLS, kimlik bilgileri ve ham okumaları ile işaretlenen aykırı değerleri yan yana izleyebileceğiniz canlı bir topic gezgini ekler. Analitiği cihazlarla birleştirmenin diğer yolları için yapay zeka ve IoT rehberine bakın.

ConnectMQ ile Başlayın

app.connectmq.com adresinde ücretsiz Serverless planında kredi kartı gerektirmeden bir broker oluşturun, sensörlerinizi ona yönlendirin ve aykırı değer dedektörünü simülatör yerine kendi verileriniz üzerinde çalıştırın.

Sık Sorulan Sorular

Sıcaklık sensörleri için en iyi aykırı değer tespiti yöntemi hangisidir?

En iyisi bir kombinasyondur: fiziksel sınırlar, sıçramalar için IQR sınırları ve yavaş kayma için küçük yumuşatma katsayılı EWMA. Sıcaklık yavaş değiştiği için EWMA özellikle etkilidir.

Kayan istatistikler için hangi pencere boyutunu kullanmalıyım?

Normal gürültüyü yakalayacak kadar zamanı kapsayın, ancak meşru değişikliklerin emilmesi çok uzun sürecek kadar fazlasını değil. Saniyede bir okuma için bir ila beş dakika makul bir başlangıç noktasıdır.

Aykırı değerler veriden silinmeli mi?

Silmek yerine işaretleyin. Kararları denetleyebilmek ve modelleri daha sonra yeniden eğitebilmek için ham değeri bir aykırı değer işaretiyle birlikte saklayın.

Bu yöntemler bir ESP32 üzerinde çalışabilir mi?

Evet. EWMA sinyal başına yalnızca iki float gerektirir ve 30 ila 60 değerlik kayan bir pencere ESP32 belleğine rahatlıkla sığar; böylece aykırı değerleri yayınlamadan önce işaretleyebilirsiniz.

İlgili yazılar

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.