Diese Funktion führt eine Anomalieerkennung für Sensordaten basierend auf dem Sensortyp durch und speichert die Ergebnisse im results["anomaly"]
-Dictionary.
sensor_df['anomaly'] = 0
anomaly_counts = {}
sensor_df['anomaly'] = 0
setzt eine neue Spalte anomaly
in sensor_df
auf 0
.anomaly_counts = {}
erstellt ein leeres Dictionary für die Zählung der Anomalien pro Sensortyp.for sensor_type in sensor_df['sensorType'].unique():
sensor_subset = sensor_df[sensor_df['sensorType'] == sensor_type]
if not sensor_subset.empty:
X_anomaly = sensor_subset[['value']]
anomaly_detector = IsolationForest(n_estimators=100, contamination=0.05, random_state=42)
anomaly_detector.fit(X_anomaly)
predictions = anomaly_detector.predict(X_anomaly)
sensor_df.loc[sensor_subset.index, 'anomaly'] = pd.Series(predictions, index=sensor_subset.index)
anomaly_count = (sensor_df.loc[sensor_subset.index, 'anomaly'] == -1).sum()
anomaly_counts[sensor_type] = anomaly_count
sensor_type
im DataFrame wird ein Subset (sensor_subset
) erstellt.X_anomaly
enthält die Spalte value
für die Analyse.IsolationForest
wird mit contamination=0.05
initialisiert, was 5 % der Daten als Anomalien markiert.anomaly_detector
wird auf X_anomaly
trainiert.predict
liefert Anomalien (markiert als -1
) und Normalwerte (1
).sensor_subset
werden in sensor_df
gespeichert.anomaly_count
zählt die -1
-Markierungen für Anomalien, und anomaly_counts
speichert sie für jeden sensor_type
.sensor_df['anomaly'] = sensor_df['anomaly'].apply(lambda x: 1 if x == -1 else 0)
-1
-Markierungen in 1
(Anomalie) und andere Werte in 0
um.results
:
for sensor_type, count in anomaly_counts.items():
results["anomaly"].append({
"sensor_type": sensor_type,
"vehicle_id": self.vehicle_id,
"anomaly_count": count,
"anomaly_data": []
})
anomalies = sensor_df[(sensor_df['sensorType'] == sensor_type) & (sensor_df['anomaly'] == 1)]
if not anomalies.empty:
results["anomaly"][-1]["anomaly_data"].extend(anomalies[['timestamp', 'value', 'mileage', 'anomaly']].to_dict(orient='records'))
results["anomaly"]
ein Dictionary erstellt mit "sensor_type"
, "vehicle_id"
, "anomaly_count"
, und "anomaly_data"
.timestamp
, value
, mileage
, anomaly
) werden als JSON-Objekte in anomaly_data
gespeichert.fig, ax = plt.subplots(figsize=(14, 6))
ax.plot(sensor_df[sensor_df['sensorType'] == sensor_type]['timestamp'],
sensor_df[sensor_df['sensorType'] == sensor_type]['value'], label='Sensorwert')
ax.scatter(anomalies['timestamp'], anomalies['value'], color='red', label='Anomalie', marker='x')
ax.set_xlabel('Zeit')
ax.set_ylabel('Sensorwert')
ax.set_title(f'Anomalieerkennung in den Sensordaten - Sensortyp: {sensor_type} - Fahrzeug-ID: {self.vehicle_id}')
ax.legend()
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
results["anomaly"][-1]["plot"] = base64.b64encode(buf.getvalue()).decode('utf-8')
plt.close(fig)
results["anomaly"][-1]["plot"]
gespeichert.Die Funktion analysiert Sensordaten nach Sensortypen, erkennt Anomalien, speichert die Anzahl und die Details der Anomalien und erstellt Diagramme zur Visualisierung.
Um die Anomalieerkennungsfunktion weniger empfindlich zu machen, kannst du die Parameter des IsolationForest
-Modells anpassen, insbesondere den Parameter contamination
, der steuert, wie viele Datenpunkte als Anomalien klassifiziert werden. Hier sind verschiedene Möglichkeiten zur Anpassung:
contamination
):
contamination=0.05
, was bedeutet, dass 5 % der Daten als Anomalien markiert werden. Wenn du diesen Wert reduzierst, wird der Algorithmus weniger empfindlich gegenüber Anomalien.contamination=0.01
kann die Anzahl der als Anomalien markierten Datenpunkte erheblich verringern.n_estimators
):
IsolationForest
(z. B. n_estimators=200
oder mehr) kann die Stabilität der Anomalieerkennung verbessern und damit Empfindlichkeitsschwankungen ausgleichen.Hier ist die angepasste Funktion:
import pandas as pd
from sklearn.ensemble import IsolationForest
import matplotlib.pyplot as plt
import base64
import io
def detect_anomalies(sensor_df, vehicle_id, debug=False, contamination=0.01, n_estimators=200):
"""
Erkennt Anomalien in Sensordaten nach Sensortyp und gibt ein Dictionary mit Anomalien und Visualisierungen zurück.
Parameter:
- sensor_df (DataFrame): DataFrame mit Sensordaten, das die Spalten 'sensorType', 'value', 'timestamp', 'mileage' enthält.
- vehicle_id (str): Die ID des Fahrzeugs, für das Anomalien erkannt werden sollen.
- debug (bool): Wenn True, zeigt Debug-Plots für jede Anomalieerkennung an.
- contamination (float): Prozentsatz der Daten, der als Anomalie markiert wird (Standardwert 0.01).
- n_estimators (int): Anzahl der Bäume im Isolation Forest (Standardwert 200).
Rückgabe:
- results (dict): Ein Dictionary mit den Anomalieergebnissen, einschließlich Zählungen, Daten und Visualisierungen.
"""
results = {"anomaly": []}
# Initialisiere die Anomaliespalte
sensor_df['anomaly'] = 0
anomaly_counts = {}
# Schleife durch jeden Sensortyp, um Anomalien zu erkennen
for sensor_type in sensor_df['sensorType'].unique():
sensor_subset = sensor_df[sensor_df['sensorType'] == sensor_type]
if not sensor_subset.empty:
X_anomaly = sensor_subset[['value']]
anomaly_detector = IsolationForest(n_estimators=n_estimators, contamination=contamination, random_state=42)
anomaly_detector.fit(X_anomaly)
predictions = anomaly_detector.predict(X_anomaly)
# Speichern der Anomalieergebnisse im sensor_df
sensor_df.loc[sensor_subset.index, 'anomaly'] = pd.Series(predictions, index=sensor_subset.index)
anomaly_count = (sensor_df.loc[sensor_subset.index, 'anomaly'] == -1).sum()
anomaly_counts[sensor_type] = anomaly_count
# Konvertiere -1 in 1 für Anomalien und 0 für normale Daten
sensor_df['anomaly'] = sensor_df['anomaly'].apply(lambda x: 1 if x == -1 else 0)
# Füge Anomalieergebnisse zu results hinzu
for sensor_type, count in anomaly_counts.items():
anomalies = sensor_df[(sensor_df['sensorType'] == sensor_type) & (sensor_df['anomaly'] == 1)]
anomaly_entry = {
"sensor_type": sensor_type,
"vehicle_id": vehicle_id,
"anomaly_count": count,
"anomaly_data": anomalies[['timestamp', 'value', 'mileage', 'anomaly']].to_dict(orient='records')
}
# Erstelle ein Diagramm für die Anomalien und speichere es als Base64-kodierten String
fig, ax = plt.subplots(figsize=(14, 6))
ax.plot(sensor_df[sensor_df['sensorType'] == sensor_type]['timestamp'],
sensor_df[sensor_df['sensorType'] == sensor_type]['value'], label='Sensorwert')
ax.scatter(anomalies['timestamp'], anomalies['value'], color='red', label='Anomalie', marker='x')
ax.set_xlabel('Zeit')
ax.set_ylabel('Sensorwert')
ax.set_title(f'Anomalieerkennung in den Sensordaten - Sensortyp: {sensor_type} - Fahrzeug-ID: {vehicle_id}')
ax.legend()
# Debug-Ausgabe der Plots
if debug:
plt.show()
# Speichern des Plots im results-Dictionary
buf = io.BytesIO()
plt.savefig(buf, format='png')
buf.seek(0)
anomaly_entry["plot"] = base64.b64encode(buf.getvalue()).decode('utf-8')
plt.close(fig)
results["anomaly"].append(anomaly_entry)
return results
contamination
: Du kannst den contamination
-Parameter beim Aufruf der Funktion ändern, um die Empfindlichkeit zu steuern. Standardwert ist 0.01
für weniger empfindliche Erkennung.n_estimators
: Durch die Erhöhung der Anzahl der Bäume auf 200
wird die Erkennung robuster.results = detect_anomalies(sensor_df, vehicle_id="V001", contamination=0.01, n_estimators=200, debug=True)
Durch diese Anpassungen wird die Anomalieerkennung weniger empfindlich auf kleine Abweichungen reagieren und dadurch robuster.
Die Ergebnisse aus der Anomalieerkennung können wertvolle Informationen für die Vorhersage eines Defekts liefern. Hier sind einige Ansätze, wie die Anomalieergebnisse in die Defektvorhersage integriert werden können:
Codebeispiel zur Feature-Erstellung:
# Beispiel: Berechne die Anzahl der Anomalien für jeden Sensor in den letzten 30 Tagen
sensor_df["anomaly_count_last_30_days"] = sensor_df.groupby("sensorType")["anomaly"].rolling('30D').sum().reset_index(level=0, drop=True)
Code zur Erstellung von Zeitabständen:
# Berechne die Zeitabstände zwischen den Anomalien für jeden Sensortyp
sensor_df["anomaly_timedelta"] = sensor_df.groupby("sensorType")["timestamp"].diff()
Codebeispiel für ein gleitendes Fenster:
# Durchschnittliche Anzahl an Anomalien im gleitenden Fenster von 30 Tagen
sensor_df["anomaly_rolling_avg_30"] = sensor_df["anomaly"].rolling(window=30).mean()
Hier ist eine angepasste Version, die anomaly_count
und anomaly_rolling_avg_30
als zusätzliche Features in das Defektvorhersagemodell integriert:
# Anomalien berechnen
sensor_df["anomaly_count"] = sensor_df.groupby("sensorType")["anomaly"].transform("sum")
sensor_df["anomaly_rolling_avg_30"] = sensor_df.groupby("sensorType")["anomaly"].rolling(window=30, min_periods=1).mean().reset_index(level=0, drop=True)
# Wähle die Features, einschließlich der Anomalie-Features
numerical_features = ["value", "mileage", "age_in_years", "past_workshop_count",
"avg_past_workshop_cost", "past_defect_count", "anomaly_count", "anomaly_rolling_avg_30"]
categorical_features = ["sensorType"]
# ColumnTransformer und Pipeline aktualisieren, um die neuen Features zu verwenden
column_transformer = ColumnTransformer(
transformers=[
("num_imputer", SimpleImputer(strategy="mean"), numerical_features),
("encoder", OneHotEncoder(), categorical_features),
("scaler", StandardScaler(), numerical_features)
],
remainder="passthrough"
)
# Model fitting und Vorhersage wie gehabt
pipeline = Pipeline([
("preprocessor", column_transformer),
("classifier", RandomForestClassifier(random_state=42, n_estimators=100, max_depth=10))
])
pipeline.fit(X_train, y_train)
Durch die Kombination der Anomalieerkennungsergebnisse mit dem Defektvorhersagemodell kannst du die Sensitivität des Modells verbessern und die Defektvorhersage präziser gestalten. Die oben genannten Methoden erlauben es dem Modell, Anomalien und ihre Häufigkeit als zusätzliche Vorboten eines möglichen Defekts zu berücksichtigen.
Die Anomalieerkennung anhand von Grenzwerten ist eine einfache und effektive Methode, um ungewöhnliche oder abnormale Werte in Sensordaten zu identifizieren. Sie basiert auf der Festlegung von oberen und unteren Schwellenwerten, die definieren, was als “normaler” Bereich für die Daten eines Sensors betrachtet wird.
sensorType
) werden obere und untere Grenzwerte festgelegt. Diese Grenzwerte können:
anomaly = 1
).-20°C
oder über 120°C
liegt, wird dies als Anomalie betrachtet.0
und 300
bar liegen sollten. Werte außerhalb dieses Bereichs werden als fehlerhaft eingestuft.Die Grenzwert-basierte Methode kann durch folgende Techniken ergänzt werden:
Die Anomalieerkennung anhand von oberen und unteren Grenzwerten ist eine effektive Methode zur Identifikation von ungewöhnlichen Werten in Sensordaten. Sie ist besonders geeignet, wenn klare Schwellenwerte bekannt sind. Für dynamische und komplexere Szenarien kann die Methode erweitert oder durch maschinelles Lernen ergänzt werden.
Autor: Jörg Harzmann
Dieser Inhalt ist unter einer CC BY-NC Lizenz veröffentlicht. Jeglicher Quellcode ist urheberrechtlich geschützt!