Sensör verisinde Isolation Forest, birkaç sinyalin birleşiminde saklanan anomalileri yakalamanın en pratik yollarından biridir. Bu eğitimde geçmiş veri üretecek, pencere özellikleri çıkaracak, scikit-learn ile bir model eğitecek ve onu canlı MQTT mesajlarını puanlayıp anomali olaylarını yayınlayan bir Python servisinde çalıştıracaksınız.
Isolation Forest Sensör Verisinde Neden İyi Çalışır
Isolation Forest basit bir fikre dayanır: anomaliler az ve farklıdır, bu yüzden yalıtılmaları daha kolaydır. Algoritma çok sayıda rastgele ağaç oluşturur; her ağaç tekrar tekrar rastgele bir özellik ve rastgele bir bölme değeri seçer. Normal noktalar yoğun bölgelerde bulunur ve ayrılmaları için çok sayıda bölme gerekir. Anormal noktalar ise yalnızca birkaç bölmeden sonra yalıtılır. Ağaçlar boyunca ortalama yol uzunluğu anomali skoruna dönüşür.
Bu tasarım, birkaç nedenle endüstriyel sensörlere uygundur:
- Etiket gerekmez. Her fabrikada bolca bulunan, çoğunlukla normal çalışma verisiyle eğitirsiniz.
- Doğası gereği çok değişkenlidir. Yüksek akım normaldir, düşük debi normaldir; ancak yüksek akımla birlikte düşük debi hızla yalıtılır.
- Hızlıdır. Yüz binlerce satır üzerinde eğitim saniyeler sürer ve puanlama bir uç gateway için yeterince ucuzdur.
- Az hiperparametre vardır. Ağaç sayısı, örneklem boyutu ve beklenen kirlilik (contamination) oranı genellikle ayarladığınız her şeydir.
Sınırları da vardır. Zamanı kendi başına anlamaz; bu yüzden zamansal davranışı özelliklere kodlamanız gerekir. Ayrıca eğitim verisine göre puanlar; yazın eğitilmiş bir model kışı anormal olarak işaretleyebilir.
Isolation Forest ile Diğer Dedektörlerin Karşılaştırması
| Yöntem | Çok değişkenli | İlgisiz özellikleri tolere eder | Eğitim maliyeti | Açıklanabilirlik |
|---|---|---|---|---|
| Kayan z-skoru | Hayır (sinyal başına) | Uygulanamaz | Yok | Yüksek |
| Isolation Forest | Evet | Oldukça iyi | Düşük | Orta |
| One-Class SVM | Evet | Zayıf, ölçekleme gerekir | Ortadan yükseğe | Düşük |
| Local Outlier Factor | Evet | Zayıf | Orta, bellek yoğun | Orta |
| Autoencoder | Evet | İyi, yeterli veriyle | Yüksek | Düşük |
Tek sinyalli istatistikleri henüz denemediyseniz, önce Z-skoru, IQR ve EWMA ile sensör verisinde aykırı değer tespiti yazısını okuyun. Isolation Forest, bu yöntemler sinyaller arasındaki ilişkileri kaçırdığında yerini hak eder.
Ön Koşullar
pip install "paho-mqtt>=2.0" scikit-learn pandas numpy joblib
connectmq/demo/if-5d21/... gibi rastgele bir önek seçin. Örnekler, tüm topic'lerin başkaları tarafından okunabildiği broker.connectmq.com genel test alanını kullanır; bu yüzden veriyi sentetik tutun.
Adım 1: Geçmiş Sensör Verisi Oluşturmak
Gerçek bir projede geçmiş veriyi veritabanınızdan dışa aktarırsınız. Eğitimi kendi içinde bütünlüklü tutmak için bu betik, birbiriyle ilişkili üç sinyale sahip bir pompayı simüle eder: motor akımı, debi ve çıkış basıncı.
# make_history.py
import numpy as np
import pandas as pd
rng = np.random.default_rng(42)
n = 20_000 # saniyede bir okuma, yaklaşık 5,5 saat
load = 0.6 + 0.2 * np.sin(np.arange(n) / 900) + rng.normal(0, 0.02, n)
df = pd.DataFrame({
"currentA": 10 + 12 * load + rng.normal(0, 0.3, n),
"flowLpm": 30 + 40 * load + rng.normal(0, 1.0, n),
"pressureBar": 2 + 3 * load + rng.normal(0, 0.08, n),
})
df.to_csv("pump_history.csv", index=False)
print(df.describe())
Üç sinyal de yükle birlikte hareket eder. Bu korelasyon, tam olarak sinyal başına bir eşiğin göremeyeceği şeydir.
Adım 2: Pencere Özellikleri Çıkarmak
Tekil okumaları puanlamak gürültüyü ve kısa dinamikleri göz ardı eder. Bunun yerine kısa bir kayan pencere üzerinde özellikler hesaplayın: her sinyalin ortalaması, standart sapması ve fiziksel olarak anlamlı birkaç oran.
# features.py
import numpy as np
import pandas as pd
SIGNALS = ["currentA", "flowLpm", "pressureBar"]
WINDOW = 10 # okuma sayısı
def window_features(frame: pd.DataFrame) -> dict:
feats = {}
for s in SIGNALS:
feats[f"{s}_mean"] = frame[s].mean()
feats[f"{s}_std"] = frame[s].std(ddof=0)
feats["flow_per_amp"] = feats["flowLpm_mean"] / max(feats["currentA_mean"], 1e-6)
feats["pressure_per_flow"] = feats["pressureBar_mean"] / max(feats["flowLpm_mean"], 1e-6)
return feats
def build_feature_table(df: pd.DataFrame, step: int = 5) -> pd.DataFrame:
rows = [window_features(df.iloc[i:i + WINDOW])
for i in range(0, len(df) - WINDOW, step)]
return pd.DataFrame(rows)
Oranlar göründüklerinden daha önemlidir. Tıkanmış bir çark amper başına debiyi, bir sızıntı ise debi başına basıncı düşürür; her ham değer normal aralığında olsa bile.
Adım 3: Isolation Forest'ı Eğitmek
# train.py
import joblib
import pandas as pd
from sklearn.ensemble import IsolationForest
from features import build_feature_table
history = pd.read_csv("pump_history.csv")
X = build_feature_table(history)
model = IsolationForest(
n_estimators=200,
max_samples=256,
contamination=0.005, # eğitim verisindeki beklenen anomali oranı
random_state=0,
)
model.fit(X)
scores = -model.score_samples(X) # yüksek = daha anormal
threshold = float(pd.Series(scores).quantile(0.995))
joblib.dump({"model": model, "columns": list(X.columns),
"threshold": threshold, "version": "iforest-pump-v1"},
"iforest_pump.joblib")
print(f"trained on {len(X)} windows, threshold={threshold:.3f}")
İki ayrıntı dikkat gerektirir. Birincisi, scikit-learn'ün score_samples fonksiyonu daha anormal noktalar için daha düşük değerler döndürür; bu yüzden onu negatif almak sezgisel bir "yüksek olan daha kötü" skoru verir. İkincisi, yalnızca predict'e güvenmek yerine eğitim skor dağılımından alınmış açık bir eşik saklayın. Böylece onu daha sonra yeniden eğitim yapmadan ayarlayabilirsiniz.
Adım 4: Canlı MQTT Mesajlarını Puanlamak
Aşağıdaki servis pompanın telemetrisine abone olur, son on okumayı tutar, aynı özellikleri hesaplar ve her okumada bir skor yayınlar.
# live_score.py
import json
import time
import uuid
from collections import deque
import joblib
import pandas as pd
import paho.mqtt.client as mqtt
from features import SIGNALS, WINDOW, window_features
PREFIX = "connectmq/demo/if-5d21/site1/pumps/pump1"
bundle = joblib.load("iforest_pump.joblib")
model, columns, threshold = bundle["model"], bundle["columns"], bundle["threshold"]
buffer = deque(maxlen=WINDOW)
streak = 0
def on_connect(client, userdata, flags, reason_code, properties):
print("connected:", reason_code)
client.subscribe(f"{PREFIX}/telemetry", qos=0)
def on_message(client, userdata, msg):
global streak
try:
reading = json.loads(msg.payload)
buffer.append({s: float(reading[s]) for s in SIGNALS})
except (ValueError, KeyError):
return
if len(buffer) < WINDOW:
return
feats = window_features(pd.DataFrame(buffer))
X = pd.DataFrame([feats], columns=columns)
score = float(-model.score_samples(X)[0])
is_anomaly = score > threshold
streak = streak + 1 if is_anomaly else 0
result = {"ts": time.time(), "score": round(score, 4),
"threshold": round(threshold, 4), "isAnomaly": is_anomaly,
"model": bundle["version"],
"flowPerAmp": round(feats["flow_per_amp"], 3)}
client.publish(f"{PREFIX}/anomaly", json.dumps(result), qos=0)
if streak == 3:
client.publish(f"{PREFIX}/alerts", json.dumps(result), qos=1)
print("ALERT", result)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"iforest-{uuid.uuid4().hex[:8]}")
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_forever()
Adım 5: Normal ve Arızalı Veri Beslemek
Bu yayıncı normal davranışı yeniden oynatır ve bir dakika sonra tıkanmış bir çarkı simüle eder: akım yüksek kalırken debi düşer.
# replay.py
import json
import time
import uuid
import numpy as np
import paho.mqtt.client as mqtt
PREFIX = "connectmq/demo/if-5d21/site1/pumps/pump1"
rng = np.random.default_rng()
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"pump-sim-{uuid.uuid4().hex[:8]}")
client.connect("broker.connectmq.com", 1883, keepalive=60)
client.loop_start()
for t in range(240):
load = 0.6 + rng.normal(0, 0.02)
reading = {
"currentA": 10 + 12 * load + rng.normal(0, 0.3),
"flowLpm": 30 + 40 * load + rng.normal(0, 1.0),
"pressureBar": 2 + 3 * load + rng.normal(0, 0.08),
}
if t > 60:
reading["flowLpm"] *= 0.75 # tıkanmış çark
client.publish(f"{PREFIX}/telemetry",
json.dumps({k: round(v, 3) for k, v in reading.items()}))
time.sleep(1)
client.loop_stop()
Önce live_score.py, ardından replay.py betiğini başlatın. Skorlar ilk dakika boyunca eşiğin altında kalır ve debi düştüğü anda keskin şekilde yükselir; çünkü akım ve basınç hâlâ olağan görünürken amper başına debi ilişkisi bozulur.
Bir Uyarıyı Teknisyene Açıklamak
Tek başına bir anomali skoru kimseye neyi kontrol etmesi gerektiğini söylemez. Isolation Forest'ın yerleşik bir özellik bazlı açıklaması yoktur; ancak ucuz bir yaklaşım pratikte iyi çalışır: her özellik için mevcut değerin eğitim dağılımından ne kadar uzakta olduğunu, örneğin eğitim medyanı ve çeyrekler açıklığına göre sağlam bir z-skoru olarak hesaplayın ve en uç iki veya üç özelliği uyarıya ekleyin.
"Skor 0,71, eşik 0,62'nin üzerinde; flow_per_amp olağandışı düşük, flowLpm_mean olağandışı düşük" diyen bir uyarı doğrudan çarka veya emiş tarafına işaret eder. Bu, "pump1 anomalisi"nden çok daha fazla aksiyona dönüştürülebilir. Daha titiz atıflara ihtiyacınız varsa ağaç toplulukları için SHAP değerleri hesaplanabilir; ancak bunlar daha fazla hesaplama gerektirir ve ilk kurulum için nadiren gereklidir.
Özellik değerlerinin kendisini de anomali topic'inde düşük bir hızla yayınlamak faydalıdır. Bir mühendis daha sonra inceleme yaptığında, yalnızca modelin kararını değil, modelin gördüğü girdileri de görebilir.
Sensör Verisinde Isolation Forest için Ayar Kontrol Listesi
- Temsil edici normal verilerle eğitin. Görmeyi beklediğiniz tüm olağan çalışma modlarını, vardiyaları ve mevsimleri dahil edin.
- Bilinen arızaları eğitimden çıkarın ya da çıkaramıyorsanız kirlilik oranını dürüstçe belirleyin.
- Özellikleri fiziksel olarak anlamlı tutun. Oranlar ve farklar çoğu zaman ham değerlerden daha iyi sonuç verir.
- Zaman damgalarını ve sayaçları özellik olarak kullanmaktan kaçının; her yeni okumayı yeni ve farklı gösterirler.
- Eşiği doğrulama verisinden belirleyin ve uyarıların ilk haftalarından sonra yeniden gözden geçirin.
- Uyarı vermeden önce süreklilik arayın, tıpkı yukarıdaki ardışıklık sayacının yaptığı gibi.
- Modeli sürümleyin ve sürümü yayınlanan her sonuca ekleyin.
- Belirli bir takvimle yeniden eğitin ya da kayma izleme girdi dağılımının değiştiğini söylediğinde.
Son madde, anomali tespitinin IoT için MLOps ile buluştuğu yerdir: dedektörün kendisi de izlenmesi gereken bir modeldir.
Üretimde Çalıştırmak
Servisi bir uç gateway'e veya verinize yakın bir sunucuya taşıyın, broker'ınızın verdiği kimlik bilgileriyle 8883 portunda TLS üzerinden bağlanın ve topic yapısını koruyun. Özel bir ConnectMQ broker'ı, skorları ham telemetrinin yanında izlemeniz için canlı bir topic gezgini sunar; portaldaki eşik tabanlı uyarı kuralları da sayısal bir score değerinin bir sınırı aştığını basit ikinci bir güvenlik ağı olarak işaretleyebilir. Broker işletmekle hiç uğraşmak istemiyorsanız, ConnectMQ gibi barındırılan bir MQTT broker sertifikaları, kimlik doğrulamayı ve çalışma süresini yönetir; modeliniz ise kendi kodunuz olarak kalır. Hesap açmadan prototipleme için broker.connectmq.com genel alanı yeterlidir.
Çevreleyen mimari için IoT anomali tespiti yöntemleri yazısına, bu servisin daha hafif, tek sinyalli bir sürümü için ise Python ile gerçek zamanlı anomali tespiti yazısına bakın. Daha geniş bağlam yapay zeka ve IoT rehberinde.
ConnectMQ ile Başlayın
app.connectmq.com adresinde ücretsiz Serverless planında kredi kartı gerektirmeden bir broker oluşturun ve live_score.py içindeki genel host'u kendi uç noktanız ve kimlik bilgilerinizle değiştirin. Isolation Forest sonuçlarınız, ilk pencere dolduğu anda topic gezgininde görünecek.
Sık Sorulan Sorular
Sensör verisinde Isolation Forest eğitmek için ne kadar veriye ihtiyacım var?
Tüm normal çalışma modlarını kapsayan birkaç bin özellik penceresi başlamak için genellikle yeterlidir. Modların kapsanması, salt veri hacminden daha önemlidir.
Hangi kirlilik (contamination) değerini kullanmalıyım?
Eğitim verisinin ne kadarının anormal olduğuna dair en iyi tahmininizi kullanın; özenle seçilmiş normal veri için bu çoğu zaman yüzde birin oldukça altındadır. Canlı servis kendi eşiğini kullandığından, kirlilik oranı esas olarak varsayılan predict çıktısını etkiler.
Isolation Forest bir mikrodenetleyicide çalışabilir mi?
Eğitilmiş ağaçlar küçüktür, ancak özellik hesaplama ve scikit-learn'ün kendisi Linux sınıfı bir cihaz gerektirir. Bunu bir gateway'de veya Raspberry Pi'de çalıştırın; mikrodenetleyicilerde basit eşiklerle devam edin.
Modelim bir proses değişikliğinden sonra neden her şeyi işaretliyor?
Isolation Forest eğitim verisine göre puanlar; bu yüzden yeni bir ürün veya set değeri anormal görünür. Yeni moddan gelen verilerle yeniden eğitin ya da her mod için ayrı modeller eğitin.



