Einführung
In diesem Lab wird gezeigt, wie man mit Scikit-Learn die Ausreißererkennung auf klassischen Anomalieerkennungsdatenmengen mit den Algorithmen Local Outlier Factor (LOF) und Isolation Forest (IForest) durchführt. Die Leistung der Algorithmen wird in einem Ausreißererkennungs-Kontext bewertet, und ROC-Kurven werden verwendet, um die Ergebnisse darzustellen.
Tipps für die VM
Nachdem der VM-Start abgeschlossen ist, klicken Sie in der oberen linken Ecke, um zur Registerkarte Notebook zu wechseln und Jupyter Notebook für die Übung zu nutzen.
Manchmal müssen Sie einige Sekunden warten, bis Jupyter Notebook vollständig geladen ist. Die Validierung von Vorgängen kann aufgrund von Einschränkungen in Jupyter Notebook nicht automatisiert werden.
Wenn Sie bei der Lernphase Probleme haben, können Sie Labby gerne fragen. Geben Sie nach der Sitzung Feedback, und wir werden das Problem für Sie prompt beheben.
Datenaufbereitung
Der erste Schritt besteht darin, die Datensatz aufzubereiten. In diesem Beispiel verwenden wir reale Datensätze aus dem datasets-Modul von Scikit-Learn. Die Stichprobengröße einiger Datensätze wird reduziert, um die Berechnung zu beschleunigen. Nach der Datenaufbereitung werden die Ziele der Datensätze zwei Klassen haben, wobei 0 für Inlier und 1 für Ausreißer steht. Die preprocess_dataset-Funktion gibt Daten und Ziel zurück.
import numpy as np
from sklearn.datasets import fetch_kddcup99, fetch_covtype, fetch_openml
from sklearn.preprocessing import LabelBinarizer
import pandas as pd
rng = np.random.RandomState(42)
def preprocess_dataset(dataset_name):
## Laden und Vektorisierung
print(f"Lade {dataset_name} Daten")
if dataset_name in ["http", "smtp", "SA", "SF"]:
dataset = fetch_kddcup99(subset=dataset_name, percent10=True, random_state=rng)
X = dataset.data
y = dataset.target
lb = LabelBinarizer()
if dataset_name == "SF":
idx = rng.choice(X.shape[0], int(X.shape[0] * 0.1), replace=False)
X = X[idx] ## Stichprobengröße reduzieren
y = y[idx]
x1 = lb.fit_transform(X[:, 1].astype(str))
X = np.c_[X[:, :1], x1, X[:, 2:]]
elif dataset_name == "SA":
idx = rng.choice(X.shape[0], int(X.shape[0] * 0.1), replace=False)
X = X[idx] ## Stichprobengröße reduzieren
y = y[idx]
x1 = lb.fit_transform(X[:, 1].astype(str))
x2 = lb.fit_transform(X[:, 2].astype(str))
x3 = lb.fit_transform(X[:, 3].astype(str))
X = np.c_[X[:, :1], x1, x2, x3, X[:, 4:]]
y = (y!= b"normal.").astype(int)
if dataset_name == "forestcover":
dataset = fetch_covtype()
X = dataset.data
y = dataset.target
idx = rng.choice(X.shape[0], int(X.shape[0] * 0.1), replace=False)
X = X[idx] ## Stichprobengröße reduzieren
y = y[idx]
## Inlier sind die mit Attribut 2
## Ausreißer sind die mit Attribut 4
s = (y == 2) + (y == 4)
X = X[s, :]
y = y[s]
y = (y!= 2).astype(int)
if dataset_name in ["glass", "wdbc", "cardiotocography"]:
dataset = fetch_openml(
name=dataset_name, version=1, as_frame=False, parser="pandas"
)
X = dataset.data
y = dataset.target
if dataset_name == "glass":
s = y == "tableware"
y = s.astype(int)
if dataset_name == "wdbc":
s = y == "2"
y = s.astype(int)
X_mal, y_mal = X[s], y[s]
X_ben, y_ben = X[~s], y[~s]
## auf 39 Punkte abgesampelt (9,8% Ausreißer)
idx = rng.choice(y_mal.shape[0], 39, replace=False)
X_mal2 = X_mal[idx]
y_mal2 = y_mal[idx]
X = np.concatenate((X_ben, X_mal2), axis=0)
y = np.concatenate((y_ben, y_mal2), axis=0)
if dataset_name == "cardiotocography":
s = y == "3"
y = s.astype(int)
## 0 repräsentiert Inlier, und 1 repräsentiert Ausreißer
y = pd.Series(y, dtype="category")
return (X, y)
Ausreißerprädiktionsfunktion
Der nächste Schritt besteht darin, eine Ausreißerprädiktionsfunktion zu definieren. In diesem Beispiel verwenden wir die Algorithmen LocalOutlierFactor und IsolationForest. Die compute_prediction-Funktion gibt den durchschnittlichen Ausreißerscore von X zurück.
from sklearn.neighbors import LocalOutlierFactor
from sklearn.ensemble import IsolationForest
def compute_prediction(X, model_name):
print(f"Berechne {model_name} Vorhersage...")
if model_name == "LOF":
clf = LocalOutlierFactor(n_neighbors=20, contamination="auto")
clf.fit(X)
y_pred = clf.negative_outlier_factor_
if model_name == "IForest":
clf = IsolationForest(random_state=rng, contamination="auto")
y_pred = clf.fit(X).decision_function(X)
return y_pred
Ergebnisse plotten und interpretieren
Der letzte Schritt besteht darin, die Ergebnisse zu plotten und zu interpretieren. Die Algorithmusleistung hängt davon ab, wie gut die True-Positive-Rate (TPR) bei einem niedrigen Wert der False-Positive-Rate (FPR) ist. Die besten Algorithmen haben die Kurve in der oberen linken Ecke des Plots und die Fläche unter der Kurve (AUC) nahe bei 1. Die diagonale durchgezogene Linie repräsentiert eine zufällige Klassifizierung von Ausreißern und Inlierern.
import math
import matplotlib.pyplot as plt
from sklearn.metrics import RocCurveDisplay
datasets_name = [
"http",
"smtp",
"SA",
"SF",
"forestcover",
"glass",
"wdbc",
"cardiotocography",
]
models_name = [
"LOF",
"IForest",
]
## Plotparameter
cols = 2
linewidth = 1
pos_label = 0 ## Mittelwert 0 gehört zur positiven Klasse
rows = math.ceil(len(datasets_name) / cols)
fig, axs = plt.subplots(rows, cols, figsize=(10, rows * 3), sharex=True, sharey=True)
for i, dataset_name in enumerate(datasets_name):
(X, y) = preprocess_dataset(dataset_name=dataset_name)
for model_idx, model_name in enumerate(models_name):
y_pred = compute_prediction(X, model_name=model_name)
display = RocCurveDisplay.from_predictions(
y,
y_pred,
pos_label=pos_label,
name=model_name,
linewidth=linewidth,
ax=axs[i // cols, i % cols],
plot_chance_level=(model_idx == len(models_name) - 1),
chance_level_kw={
"linewidth": linewidth,
"linestyle": ":",
},
)
axs[i // cols, i % cols].set_title(dataset_name)
plt.tight_layout(pad=2.0) ## Abstand zwischen den Teilplots
plt.show()
Zusammenfassung
In diesem Lab wurde gezeigt, wie man mit Scikit-Learn die Ausreißererkennung auf klassischen Anomalieerkennungsdatenmengen mit den Algorithmen Local Outlier Factor (LOF) und Isolation Forest (IForest) durchführt. Die Leistung der Algorithmen wurde in einem Ausreißererkennungs-Kontext bewertet, und ROC-Kurven wurden verwendet, um die Ergebnisse darzustellen.