Anomalieerkennung mit Random Forest und PyTorch

10.07.2023Frederik Möllers
Tech Artificial Intelligence Machine Learning

Figure: PyTorch, the PyTorch logo and any related marks are trademarks of The Linux Foundation.

Mit Hilfe von Machine Learning Algorithmen können aus großen Datensätzen viele interessante und wertvolle Informationen gewonnen werden. Je nach Anwendungsfall eignen sich verschiedene Algorithmen für unterschiedliche Szenarien. In vorherigen TechUps hat Stefan bereits die Grundlagen von neuronalen Netzen erläutert und wir haben gesehen, wie man mit dem Random Forest Algorithmus die Überlebenswahrscheinlichkeit von Passagieren auf dem Titanic-Schiff vorhersagen kann. In diesem TechUp wollen wir uns mit einem weiteren Verfahren beschäftigen, das uns dabei hilft, Muster in Daten zu erkennen: der Anomaly Detection, zu Deutsch Anomalieerkennung.

Was ist Anomaly Detection?

Anomaly Detection ist ein Verfahren, mit dem wir herausfinden möchten, ob ein bestimmtes Ereignis bezogen auf einen Datensatz der Norm entspricht oder nicht. Es gibt viele Anwendungsfälle, die dies verdeutlichen können.

Nehmen wir zum Beispiel die Sensorik einer Maschine, die Datenpunkte über Vibrationen an verschiedenen Messpunkten liefert. Wenn wir diese Daten über einen längeren Zeitraum aufzeichnen, können wir Muster erkennen, die zeigen, welche Art von Vibrationen die Maschine normalerweise aufweist. Sobald Datenpunkte gemessen werden, die von diesen Mustern abweichen, können wir davon ausgehen, dass die Maschine nicht mehr im Normalzustand ist. Dies kann ein Hinweis darauf sein, dass die Maschine defekt ist und repariert werden muss.

Weitere Anwendungsfälle gibt es in vielen Bereichen:

  • Cybersecurity (z.B. Erkennung von Anomalien im Netzwerkverkehr)
  • Betrugserkennung (z.B. Kreditkartenbetrug oder Versicherungsbetrug)
  • Gesundheitswesen (z.B. Erkennung seltener Krankheiten)
  • Straßenverkehr (z.B. Erkennung von Unfällen)

Wie funktioniert Anomaly Detection?

Wie wir gesehen haben, gibt es viele Anwendungsfälle, in denen Anomaly Detection eingesetzt werden kann. Wenn wir Machine Learning Algorithmen verwenden möchten, um Anomalien zu erkennen, gibt es zwei verschiedene Ansätze, die wir uns im Folgenden anschauen werden.

Bevor wir uns jedoch Gedanken über das Training von Modellen machen, sollten wir uns zunächst Gedanken über die Datengrundlage machen. Um Anomalien erkennen zu können, werden zunächst Daten benötigt, die den Normalzustand darstellen. Je nach Algorithmus werden möglicherweise auch klassifizierte Daten benötigt, die ausreichend von der Norm abweichen, um überhaupt als Anomalie klassifiziert werden zu können. Vor allem bei der Anomaly Detection ist die Qualität der Datengrundlage entscheidend. Betrachten wir zum Beispiel die Betrugserkennung: Wir können davon ausgehen, dass die Mehrheit der Datenpunkte nicht betrügerisch ist. Wenn die wenigen betrügerischen Datenpunkte nicht ausreichend repräsentativ sind oder falsch klassifiziert wurden, kann unser Algorithmus falsche Vorhersagen treffen. Dies kann in diesem Fall zu einer Über- oder Unterklassifizierung führen, die je nach Einsatzgebiet schwere Folgen haben kann.

Nun, sobald die Qualität der Datengrundlage gesichert ist, können wir uns Gedanken über die Algorithmen machen. Hier unterscheidet man zwischen zwei verschiedenen Ansätzen: Supervised Learning und Unsupervised Learning. Wenn wir einen Supervised Learning Algorithmus verwenden möchten, muss unser Datensatz klassifiziert sein, das heißt jeder Datenpunkt muss entweder als Normalzustand oder Anomalie klassifiziert sein. Je nach Anwendungsfall kann es schwierig sein, solche Daten zu generieren.

Betrachten wir das Beispiel der Sensorik einer Maschine, würden wir erwarten, dass im Normalfall wenige bis keine Anomalien auftreten. Wenn wir jedoch einen Supervised-Ansatz wählen möchten, müssten wir entweder Daten über relativ lange Zeiträume sammeln oder die Maschine gezielt beschädigen oder stören, um Anomalidatenpunkte zu erzeugen. Die Sensordaten korrekt zu klassifizieren, ist auch nicht unbedingt einfach. In solchen Fällen eignet sich ein Unsupervised Learning Algorithmus besser, der keine vorher klassifizierten Daten benötigt, sondern Anhand von Mustererkennung die Anomalien selbst erkennt.

Beispiel: Anomaly Detection anhand von Kreditkartenbetrug

Um die beiden Ansätze zu veranschaulichen, betrachten wir als Beispiel einen Datensatz über Kreditkartenbetrug. Die Daten umfassen insgesamt knapp 284.000 Kreditkartentransaktionen an zwei Tagen im September 2013, von denen 492 als betrügerisch klassifiziert wurden. Das Datenset kann von Kaggle heruntergeladen werden.

Insgesamt stehen uns 30 numerische Merkmale zur Verfügung, von denen 28 das Ergebnis einer Principal Component Analysis (PCA) Transformation der Originaldaten sind. Die anderen beiden Merkmale sind der Zeitpunkt und der Betrag der Transaktion. Aufgrund von Anonymisierungsmaßnahmen sind keine weiteren Informationen zu den einzelnen Features bekannt.

Da wir klassifizierte Daten vorliegen haben, können wir einen Supervised-Learning-Ansatz verwenden. Hier werden wir den Random Forest Algorithmus einsetzen, den wir bereits in meinem TechUp zu Decision Trees kennengelernt haben.

Als weiteren Ansatz werden wir nach diesem Beispiel auch Autoencoder zur Veranschaulichung eines Unsupervised-Learning-Algorithmus vorstellen.

Anomaly Detection mit Random Forest

Mit dem Random Forest Algorithmus lässt sich ein Modell trainieren, welches einzelne Datenpunkte anhand der Features klassifizieren kann. Um das Modell zu trainieren, benötigen wir klassifizierte Daten, die wir in unserem Datensatz vorfinden. Wir werden nun das Modell trainieren und anschließend die Vorhersagen des Modells mit den tatsächlichen Klassifikationen vergleichen. 🤓

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report, confusion_matrix
import matplotlib.pyplot as plt
import seaborn as sns

# Loading the Credit Card Fraud Detection dataset from Kaggle
df = pd.read_csv('creditcard.csv')

# Splitting the dataset into training and testing sets
X_train, X_test, y_train, y_test = train_test_split(df.drop('Class', axis=1), df['Class'], test_size=0.3, random_state=42)

# Creating a Random Forest classifier object
rfc = RandomForestClassifier(n_estimators=100, random_state=42)
# Fitting the Random Forest classifier to the training data
rfc.fit(X_train, y_train)

# Making predictions on the testing data
y_pred = rfc.predict(X_test)

# Printing the confusion matrix and classification report
print(confusion_matrix(y_test, y_pred))
print(classification_report(y_test, y_pred))

# Plotting the confusion matrix
cm = confusion_matrix(y_test, y_pred)
sns.heatmap(cm, annot=True, fmt='g', cmap='Blues')
plt.xlabel('Predicted')
plt.ylabel('Actual')
plt.title('Confusion matrix')
plt.show()

Die Resultate sind trotz des geringen Aufwands ziemlich sehenswert:

Anomaly Detection mit Autoencodern

Bei Autoencodern handelt es sich um eine spezielle Art bzw. Architektur von neuronalen Netzen, die darauf ausgelegt sind, Daten zu komprimieren. Die Idee hinter Autoencodern lässt sich am besten mithilfe einer Abbildung erklären:

Wir sehen ein neuronales Netz mit einem Input, einem Output und drei Hidden-Layers. Alle Layer sind vollständig vernetzt, das heißt, alle Neuronen sind mit allen Neuronen der vorherigen und nachfolgenden Layers verbunden. Wie man sieht, verringert sich die Anzahl der Neuronen von Layer zu Layer und das Netz ist in der Mitte gespiegelt.

Das Besondere an Autoencodern ist die Art und Weise, wie sie trainiert werden. Das Netz wird darauf trainiert, denselben Output wie Input zu liefern. Nehmen wir als Beispiel unseren Datensatz, würden wir für jedes Merkmal in jedem Datenpunkt die gleichen Werte im Output erwarten. Die Verjüngung der Layers führt dazu, dass das Netz die Input-Daten auf die wichtigsten Eigenschaften bzw. Informationen komprimieren muss, um diese im Output wieder zu reproduzieren.

Das trainierte Modell hat nun die Struktur der Trainingsdaten gelernt und kann neue Datenpunkte anhand dieser Struktur klassifizieren. Möchte man jetzt einen neuen Datenpunkt klassifizieren, so wird dieser durch das Netz gepushed und die Ausgabe des Netzwerks wird mit dem Input verglichen. Je größer der Unterschied zwischen Input und Output ist, desto stärker weicht der Datenpunkt von der Struktur der Trainingsdaten ab und desto wahrscheinlicher ist es, dass es sich um eine Anomalie handelt. Cool, oder? 😎

Im Folgenden trainieren wir einen Autoencoder mit PyTorch und verwenden diesen, um neue Datenpunkte zu klassifizieren.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split

data = pd.read_csv("creditcard.csv")

scaler = Normalizer()
data.iloc[:, 1:29] = scaler.fit_transform(data.iloc[:, 1:29])

# Scale the data
scaler = MinMaxScaler()
data.iloc[:, 1:29] = scaler.fit_transform(data.iloc[:, 1:29])

# Separate the non-fraud cases
non_fraud_data = data[data.Class == 0].iloc[:, 1:29].values
fraud_data = data[data.Class == 1].iloc[:, 1:29].values


# Define the autoencoder architecture
class Autoencoder(nn.Module):
    def __init__(self):
        super(Autoencoder, self).__init__()
        self.encoder = nn.Sequential(
            nn.Linear(28, 16),
            nn.ELU(True),
            nn.Linear(16, 8),
            nn.ELU(True),
            nn.Linear(8, 4),
            nn.ELU(True))
        self.decoder = nn.Sequential(
            nn.Linear(4, 8),
            nn.ELU(True),
            nn.Linear(8, 16),
            nn.ELU(True),
            nn.Linear(16, 28),
            nn.ELU(True))

    def forward(self, x):
        x = self.encoder(x)
        x = self.decoder(x)
        return x

# Initialize the autoencoder
autoencoder = Autoencoder()

# Define the loss function and optimizer
criterion = nn.MSELoss()
optimizer = optim.Adam(autoencoder.parameters(), lr=0.01)

# Train the autoencoder
num_epochs = 20
batch_size = 256
for epoch in range(num_epochs):
    np.random.shuffle(non_fraud_data)
    for i in range(0, len(non_fraud_data), batch_size):
        batch = non_fraud_data[i:i+batch_size]
        batch = torch.FloatTensor(batch)
        optimizer.zero_grad()
        outputs = autoencoder(batch)
        loss = criterion(outputs, batch)
        loss.backward()
        optimizer.step()
    print('Epoch [{}/{}], Loss: {:.4f}'.format(epoch+1, num_epochs, loss.item()))

Das trainierte Modell können wir jetzt mit den vorklassifizierten Datenpunkten evaluieren. Hierfür vergleichen wir die Differenzen zwischen dem Input und Output des Autoencoders (Loss) von einem Subset der Nicht-Fraud-Datenpunkte mit denen der Fraud-Datenpunkte. Je grösser der Unterschied zwischen den beiden Datensätzen ist, desto besser ist das Modell darin, Anomalien zu erkennen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
non_fraud_loss = []
for i in range(0, 500):
    x = torch.FloatTensor(non_fraud_data[i])
    output = autoencoder(x)
    loss = criterion(output, x)
    non_fraud_loss.append(loss.item())

fraud_loss = []
for i in range(0, len(fraud_data)):
    x = torch.FloatTensor(fraud_data[i])
    output = autoencoder(x)
    loss = criterion(output, x)
    fraud_loss.append(loss.item())

bins = np.linspace(0, 0.04, 200)
plt.hist(non_fraud_loss, bins, alpha=0.5, color='green', label='Non-Fraud')
plt.hist(fraud_loss, bins, alpha=0.5, color='red', label='Fraud')
plt.xlabel('Loss')
plt.ylabel('Count')
plt.legend(loc='upper right')
plt.show()

Wie man in der Abbildung schön sehen kann, unterscheiden sich die Loss-Werte der Fraud-Datenpunkte zu einem grossen Teil deutlich von denen der Nicht-Fraud-Datenpunkte. Wir können nun einen Schwellenwert definieren, ab welchem ein Datenpunkt als Anomalie klassifiziert wird.

Natürlich ist unsere Klassifikation nicht optimal, was anhand der Überlappung der beiden Histogramme zu sehen ist. Ob Autoencoder bei der Erkennnung von Anomalien das richtige Werkzeug sind, hängt stark von den Daten ab und muss immer individuell evaluiert werden.

Fazit

Ich hoffe ich konnte euch mit diesem TechUp einen interessanten Einblick in den Bereich Anomaly Detection geben. Es gibt viele Bereiche in welchen man durch das Erkennen von Datenpunkten, welche von der (vermeintlichen) Norm abweichen, wertvolle Informationen gewinnen kann. Bleib dran! 🙌

Lies doch gleich noch Stefans TechUp zu den Grundlagen neuronaler Netze! 🚀