In der Welt des maschinellen Lernens ist ein ausgeglichenes Dataset oft die Grundlage für robuste Modelle. Doch in der Praxis sind Daten oft unausgeglichen (imbalanced), was bedeutet, dass die Verteilung der Zielvariablen stark von einer Klasse dominiert wird. Dies kann zu einem Modell führen, das auf die Mehrheitsklasse verzerrt ist und die Minderheitsklasse ignoriert. In diesem Artikel erkläre ich, wie man mit unausgeglichenen Daten umgeht, mit Fokus auf Techniken wie SMOTE (Synthetic Minority Oversampling Technique), ADASYN (Adaptive Synthetic Sampling) und andere Ansätze
Warum ist Imbalanced Data ein Problem?
Ein Beispiel: Stellen Sie sich ein Dataset zur Vorhersage von Kreditkartenbetrug vor, bei dem nur 1 % der Transaktionen betrügerisch sind. Ein Modell könnte eine Genauigkeit von 99 % erreichen, indem es alle Transaktionen als nicht betrügerisch klassifiziert – aber es hätte keinerlei praktischen Nutzen.
Unausgeglichene Daten führen dazu, dass:
- Die Minderheitsklasse oft ignoriert wird.
- Metriken wie Genauigkeit (Accuracy) irreführend sind.
- Algorithmen Schwierigkeiten haben, allgemeine Muster zu erkennen.
Techniken zur Handhabung von Imbalanced Data
1. Datenbasierte Techniken
a) Oversampling
Bei Oversampling werden zusätzliche Beispiele für die Minderheitsklasse generiert, um das Ungleichgewicht auszugleichen.
i) SMOTE (Synthetic Minority Oversampling Technique)
SMOTE, entwickelt von Chawla et al. (2002), ist eine der einflussreichsten Techniken im Bereich Imbalanced Learning. Anders als beim einfachen Random Oversampling, das nur existierende Beispiele dupliziert, erzeugt SMOTE neue, synthetische Beispiele der Minderheitsklasse.
Funktionsweise von SMOTE:
- Erzeuge einen neuen synthetischen Datenpunkt auf der Verbindungslinie zwischen dem Original und dem gewählten Nachbarn
- Für jedes Beispiel der Minderheitsklasse:
- Finde die k-nächsten Nachbarn (typischerweise k=5)
- Wähle zufällig einen dieser Nachbarn aus
import numpy as np
import matplotlib.pyplot as plt
from imblearn.over_sampling import SMOTE
from sklearn.datasets import make_classification
# Erstellen eines imbalancierten Datensatzes
X, y = make_classification(n_samples=1000, n_features=2, n_redundant=0,
n_clusters_per_class=1, weights=[0.99, 0.01],
class_sep=0.8, random_state=42)
# SMOTE anwenden
smote = SMOTE(random_state=42)
X_smote, y_smote = smote.fit_resample(X, y)
# Visualisierung
plt.figure(figsize=(15, 5))
# Original Data
plt.subplot(1, 2, 1)
plt.scatter(X[y == 0, 0], X[y == 0, 1], label='Mehrheitsklasse')
plt.scatter(X[y == 1, 0], X[y == 1, 1], label='Minderheitsklasse')
plt.title('Originaldaten')
plt.legend()
# SMOTE-balanced Data
plt.subplot(1, 2, 2)
plt.scatter(X_smote[y_smote == 0, 0], X_smote[y_smote == 0, 1], label='Mehrheitsklasse')
plt.scatter(X_smote[y_smote == 1, 0], X_smote[y_smote == 1, 1], label='Minderheitsklasse (mit SMOTE)')
plt.title('Nach SMOTE')
plt.legend()
Vorteile:
- Vermeidet Overfitting im Vergleich zu einfachem Oversampling
- Erzeugt diversere Beispiele als simple Duplikation
- Gut dokumentiert und weit verbreitet
Nachteile:
- Kann Noise einführen, besonders in Grenzregionen
- Berücksichtigt nicht die Verteilung der Mehrheitsklasse
- Kann zu einer Überverallgemeinerung führen
ii) ADASYN (Adaptive Synthetic Sampling)
ADASYN, entwickelt von He et al. (2008), ist eine Weiterentwicklung von SMOTE. Der Hauptunterschied liegt darin, dass ADASYN die Schwierigkeit der Lernbeispiele berücksichtigt und mehr synthetische Daten für „schwierigere“ Fälle generiert.
Funktionsweise von ADASYN:
- Generiere proportional mehr synthetische Beispiele für höhere r_i-Werte
- Für jedes Beispiel der Minderheitsklasse:
- Berechne den „Schwierigkeitsgrad“ r_i basierend auf den k-nächsten Nachbarn
- r_i ist der Anteil der Mehrheitsklasse in der Nachbarschaft
from imblearn.over_sampling import ADASYN
# ADASYN Beispiel mit Visualisierung
ada = ADASYN(random_state=42)
X_ada, y_ada = ada.fit_resample(X, y)
plt.figure(figsize=(15, 5))
# Original Data
plt.subplot(1, 2, 1)
plt.scatter(X[y == 0, 0], X[y == 0, 1], label='Mehrheitsklasse')
plt.scatter(X[y == 1, 0], X[y == 1, 1], label='Minderheitsklasse')
plt.title('Originaldaten')
plt.legend()
# ADASYN-balanced Data
plt.subplot(1, 2, 2)
plt.scatter(X_ada[y_ada == 0, 0], X_ada[y_ada == 0, 1], label='Mehrheitsklasse')
plt.scatter(X_ada[y_ada == 1, 0], X_ada[y_ada == 1, 1], label='Minderheitsklasse (mit ADASYN)')
plt.title('Nach ADASYN')
plt.legend()
# Berechnung der lokalen Verteilung
def calculate_difficulty(X, y, k=5):
from sklearn.neighbors import NearestNeighbors
nn = NearestNeighbors(n_neighbors=k)
nn.fit(X)
difficulties = []
minority_indices = np.where(y == 1)[0]
for idx in minority_indices:
neighbors = nn.kneighbors([X[idx]], return_distance=False)[0]
difficulty = sum(y[neighbors] == 0) / k
difficulties.append(difficulty)
return difficulties
# Beispiel für die Verwendung von ADASYN mit spezifischen Parametern
adasyn = ADASYN(
n_neighbors=5, # Anzahl der Nachbarn für die Schwierigkeitsberechnung
random_state=42,
sampling_strategy=1.0 # Ausgleich auf 1:1 Verhältnis
)
Vorteile:
- Adaptiv: Berücksichtigt lokale Verteilungen
- Fokussiert auf schwierige Beispiele
- Kann bessere Ergebnisse als SMOTE bei komplexen Entscheidungsgrenzen liefern
Nachteile:
- Computationell aufwendiger als SMOTE
- Kann bei sehr verrauschten Daten zu Overfitting führen
- Sensibel gegenüber der Wahl von k
b) Undersampling
Hierbei wird die Mehrheit der Daten der dominanten Klasse entfernt. Dies ist nützlich bei sehr großen Datensätzen, kann jedoch zu Informationsverlust führen.
from imblearn.under_sampling import RandomUnderSampler
undersampler = RandomUnderSampler(random_state=42)
X_resampled, y_resampled = undersampler.fit_resample(X, y)
print("Resampled Klassenverteilung (Undersampling):", dict(zip(*np.unique(y_resampled, return_counts=True))))
2. Algorithmische Techniken
a) Klassengewicht anpassen
Viele Algorithmen wie Logistic Regression, Random Forest und SVM bieten die Möglichkeit, die Gewichtung der Klassen anzupassen.
Beispiel:
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report
model = RandomForestClassifier(class_weight="balanced", random_state=42)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print(classification_report(y_test, y_pred))
b) Anomalieerkennung
Statt ein Klassifikationsproblem zu betrachten, kann die Minderheitsklasse als Anomalie definiert werden, was spezielle Algorithmen wie Isolation Forest oder One-Class SVM erfordert.
3. Datentransformationen
a) Feature Scaling
Feature-Transformationen wie Skalierung und Normalisierung können helfen, den Einfluss dominanter Merkmale zu reduzieren.
b) Dimensionalitätsreduktion
Mit Techniken wie PCA (Principal Component Analysis) können redundante Informationen entfernt werden.
Modellbewertung bei Imbalanced Data
Es ist wichtig, Metriken zu wählen, die das Ungleichgewicht berücksichtigen:
- Precision, Recall, F1-Score: Besser als reine Genauigkeit.
- ROC-AUC (Receiver Operating Characteristic – Area Under Curve): Zeigt die Balance zwischen Sensitivität und Spezifität.
- Precision-Recall-Kurve: Besonders geeignet für stark unausgeglichene Datensätze.
from sklearn.metrics import classification_report, roc_auc_score, confusion_matrix
# Confusion Matrix und Scores berechnen
print(confusion_matrix(y_test, y_pred))
print("ROC-AUC:", roc_auc_score(y_test, model.predict_proba(X_test)[:, 1]))
print(classification_report(y_test, y_pred))
Fazit
Der Umgang mit Imbalanced Data erfordert eine Kombination aus kreativen Datenmanipulationen, geeigneten Algorithmen und der richtigen Wahl von Bewertungsmetriken. Techniken wie SMOTE und ADASYN bieten elegante Lösungen, indem sie die Minderheitsklasse verstärken, ohne die Originaldaten zu stark zu verändern. In Verbindung mit algorithmischen Anpassungen wie Klassengewichten und einer sorgfältigen Evaluierung können robuste Modelle auch mit schwierigen Datensätzen trainiert werden.
Nutzen Sie diese Techniken, um das Beste aus Ihren Daten herauszuholen und die Genauigkeit Ihrer Vorhersagen zu verbessern!