Inhaltsverzeichnis
- Was ist Unsupervised Learning?
- Clustering – Grundkonzepte
- Algorithmus: K-Means
- Algorithmus: DBSCAN
- Algorithmus: Hierarchisches Clustering
- Clusteranzahl bestimmen
- Dimensionsreduktion – Grundkonzepte
- Algorithmus: PCA – Principal Component Analysis
- Algorithmus: t-SNE
- Anwendungsbeispiel: Kundensegmentierung
- Vergleich der Algorithmen
- Zusammenfassung und Ausblick
- Anhang: Schnellreferenz
Unsupervised Learning – Clustering und Dimensionsreduktion
Fach: Data Science & Artificial Intelligence
Schulstufe: 12. Schulstufe – HTL Informatik
Voraussetzungen: Supervised Learning, Python / scikit-learn, NumPy, Matplotlib
Autor: HTL Pinkafeld – IF/IT
1. Was ist Unsupervised Learning?
Beim Supervised Learning haben wir zu jedem Datenpunkt ein Label – eine bekannte Antwort, auf die das Modell hintrainiert wird. Beim Unsupervised Learning gibt es diese Labels nicht. Der Algorithmus bekommt nur die Eingabedaten und soll selbstständig Strukturen, Muster oder Gruppierungen darin finden.
Vergleich der Lernparadigmen
| Supervised Learning | Unsupervised Learning | |
|---|---|---|
| Labels vorhanden | ✅ Ja | ❌ Nein |
| Ziel | Vorhersage | Strukturentdeckung |
| Bewertung | Accuracy, F1, RMSE, ... | Schwieriger (kein Referenzwert) |
| Beispiele | Klassifikation, Regression | Clustering, Dimensionsreduktion |
Typische Anwendungsfälle
- Kundensegmentierung: Kunden nach Kaufverhalten in Gruppen einteilen
- Anomalieerkennung: Ungewöhnliche Transaktionen (Kreditkartenbetrug) finden
- Dokumentengruppierung: Nachrichtenartikel thematisch clustern
- Empfehlungssysteme: Ähnliche Nutzerprofile identifizieren
- Datenkompression: Bilder oder Signale vereinfachen ohne wesentlichen Informationsverlust
- Visualisierung: Hochdimensionale Daten in 2D/3D darstellen
Hauptgebiete
Unsupervised Learning
│
├── Clustering
│ ├── K-Means
│ ├── DBSCAN
│ └── Hierarchisches Clustering
│
└── Dimensionsreduktion
├── PCA (Principal Component Analysis)
└── t-SNE
2. Clustering – Grundkonzepte
Clustering (dt. Clusteranalyse) bezeichnet das Gruppieren von Datenpunkten so, dass Punkte innerhalb einer Gruppe (Cluster) möglichst ähnlich sind und Punkte aus verschiedenen Gruppen möglichst unähnlich.
Distanzmaße
Ähnlichkeit wird meist über eine Distanz definiert:
Euklidische Distanz (häufigste Wahl):
d(A, B) = √( Σ (aᵢ - bᵢ)² )
Manhattan-Distanz (robuster bei Ausreißern):
d(A, B) = Σ |aᵢ - bᵢ|
Kosinus-Ähnlichkeit (für Texte und Vektoren):
cos(A, B) = (A · B) / (‖A‖ · ‖B‖)
⚠️ Wichtig: Vor dem Clustering müssen Features skaliert werden (z.B. mit
StandardScaler), da sonst Features mit großem Wertebereich die Distanzberechnung dominieren.
Qualität eines Clusterings bewerten
Da es keine Labels gibt, brauchen wir andere Bewertungsmaße:
| Metrik | Bedeutung | Bereich |
|---|---|---|
| Silhouette Score | Wie gut ist jeder Punkt in seinem Cluster? | -1 bis +1 (höher = besser) |
| Inertia (SSE) | Summe der quadrierten Abstände zum Clusterzentrum | 0 bis ∞ (niedriger = besser) |
| Davies-Bouldin Index | Ähnlichkeit zwischen Clustern | 0 bis ∞ (niedriger = besser) |
3. Algorithmus: K-Means
3.1 Grundidee
K-Means teilt die Daten in k Cluster auf, indem es iterativ Clusterzentren (Centroids) anpasst.
3.2 Algorithmus Schritt für Schritt
1. Wähle k zufällige Punkte als initiale Centroids
2. Wiederhole bis Konvergenz:
a) Zuweisung: Weise jeden Datenpunkt dem nächsten Centroid zu
b) Update: Berechne neue Centroids als Mittelwert der zugewiesenen Punkte
3. Stoppe, wenn sich die Centroids nicht mehr verändern
Visualisierung eines Iterationsschritts:
Iteration 1: Iteration 2: Iteration 3 (konvergiert):
× · · × · · ×· ·
· · × · · · × ·· ···×··
· · × · · × · ·×
× = Centroid · = Datenpunkt (Farbe = zugewiesenes Cluster)
3.3 Implementierung
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
# Synthetische Daten erstellen (3 Cluster)
X, y_true = make_blobs(n_samples=300, centers=3, cluster_std=0.8, random_state=42)
# Skalieren
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# K-Means Modell
kmeans = KMeans(n_clusters=3, n_init=10, random_state=42)
kmeans.fit(X_scaled)
labels = kmeans.labels_
centroids = kmeans.cluster_centers_
inertia = kmeans.inertia_
print(f"Inertia: {inertia:.2f}")
print(f"Silhouette Score: {silhouette_score(X_scaled, labels):.3f}")
# Visualisierung
plt.figure(figsize=(8, 5))
plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, cmap='tab10', alpha=0.6, s=40)
plt.scatter(centroids[:, 0], centroids[:, 1], c='black', marker='X', s=200, label='Centroids')
plt.title('K-Means Clustering (k=3)')
plt.legend()
plt.tight_layout()
plt.show()
3.4 Stärken und Schwächen
| ✅ Stärken | ❌ Schwächen |
|---|---|
| Einfach und schnell | k muss vorher bekannt sein |
| Skaliert gut auf große Datensätze | Empfindlich auf initiale Centroids |
| Leicht interpretierbar | Nur kugelförmige Cluster |
| Gut für kompakte, gut getrennte Cluster | Empfindlich auf Ausreißer |
| Nicht geeignet für unterschiedlich große Cluster |
4. Algorithmus: DBSCAN
4.1 Grundidee
DBSCAN (Density-Based Spatial Clustering of Applications with Noise) findet Cluster basierend auf der lokalen Datendichte. Er kann beliebig geformte Cluster erkennen und markiert Punkte in dünn besiedelten Regionen automatisch als Ausreißer (Noise).
4.2 Schlüsselbegriffe
- ε (eps): Maximaler Radius für die Nachbarschaft eines Punktes
- minPts: Mindestanzahl von Punkten in der ε-Umgebung, damit ein Punkt ein Core Point ist
- Core Point: Hat mindestens
minPtsNachbarn im Radius ε - Border Point: Liegt im Radius eines Core Points, hat aber selbst zu wenige Nachbarn
- Noise Point: Weder Core noch Border → Ausreißer, Label = -1
4.3 Implementierung
from sklearn.cluster import DBSCAN
from sklearn.datasets import make_moons
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score
import matplotlib.pyplot as plt
# Mondsichelförmige Daten (K-Means würde hier versagen)
X, _ = make_moons(n_samples=300, noise=0.08, random_state=42)
X_scaled = StandardScaler().fit_transform(X)
# DBSCAN
db = DBSCAN(eps=0.3, min_samples=5)
labels = db.fit_predict(X_scaled)
n_cluster = len(set(labels)) - (1 if -1 in labels else 0)
n_noise = (labels == -1).sum()
print(f"Gefundene Cluster: {n_cluster}")
print(f"Ausreißer: {n_noise}")
if n_cluster > 1:
mask = labels != -1
print(f"Silhouette Score: {silhouette_score(X_scaled[mask], labels[mask]):.3f}")
# Visualisierung
plt.scatter(X_scaled[:, 0], X_scaled[:, 1],
c=labels, cmap='tab10', alpha=0.7, s=40)
# Ausreißer separat markieren
noise_mask = labels == -1
plt.scatter(X_scaled[noise_mask, 0], X_scaled[noise_mask, 1],
c='red', marker='x', s=80, label='Ausreißer')
plt.title(f'DBSCAN: {n_cluster} Cluster, {n_noise} Ausreißer')
plt.legend()
plt.tight_layout()
plt.show()
4.4 Stärken und Schwächen
| ✅ Stärken | ❌ Schwächen |
|---|---|
| Keine Angabe von k nötig | eps und minPts schwer zu wählen |
| Beliebig geformte Cluster | Probleme bei unterschiedlicher Dichte |
| Erkennt Ausreißer automatisch | Schlecht bei hochdimensionalen Daten |
| Robust gegenüber Ausreißern | Langsamer als K-Means |
5. Algorithmus: Hierarchisches Clustering
5.1 Grundidee
Hierarchisches Clustering baut eine Baumstruktur (Dendrogram) auf, die alle Zusammenführungen von Clustern zeigt. Man braucht k nicht vorab festlegen – die Anzahl der Cluster wird durch einen Schnitt im Dendrogram bestimmt.
Agglomeratives Verfahren (bottom-up):
1. Jeder Datenpunkt = eigenes Cluster
2. Füge die zwei ähnlichsten Cluster zusammen
3. Wiederhole bis nur noch 1 Cluster übrig
5.2 Linkage-Methoden
Wie wird die Distanz zwischen zwei Clustern berechnet?
| Methode | Beschreibung | Geeignet für |
|---|---|---|
ward |
Minimiert Varianzanstieg | Kompakte, gleich große Cluster |
complete |
Maximale Distanz zweier Punkte | Gut getrennte Cluster |
average |
Mittlere Distanz | Ausgewogener Ansatz |
single |
Minimale Distanz (nächstes Paar) | Kettenförmige Cluster |
5.3 Implementierung mit Dendrogram
from sklearn.cluster import AgglomerativeClustering
from scipy.cluster.hierarchy import dendrogram, linkage
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
import numpy as np
X, _ = make_blobs(n_samples=50, centers=3, random_state=42)
# Dendrogram zeichnen
linked = linkage(X, method='ward')
plt.figure(figsize=(12, 5))
dendrogram(linked, leaf_rotation=90, leaf_font_size=8)
plt.axhline(y=10, color='red', linestyle='--', label='Schnitt → 3 Cluster')
plt.title('Dendrogram – Hierarchisches Clustering')
plt.xlabel('Datenpunkt-Index')
plt.ylabel('Distanz')
plt.legend()
plt.tight_layout()
plt.show()
# Cluster-Labels extrahieren (Schnitt bei k=3)
hc = AgglomerativeClustering(n_clusters=3, linkage='ward')
labels = hc.fit_predict(X)
print(f"Cluster-Größen: {np.bincount(labels)}")
6. Clusteranzahl bestimmen
6.1 Ellbow-Methode
Die Inertia wird für verschiedene k-Werte berechnet. An der „Ellbogen"-Stelle flacht die Kurve ab – das ist ein guter Hinweis auf die optimale Anzahl.
from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
import matplotlib.pyplot as plt
X, _ = make_blobs(n_samples=300, centers=4, random_state=42)
inertias = []
k_range = range(1, 11)
for k in k_range:
km = KMeans(n_clusters=k, n_init=10, random_state=42)
km.fit(X)
inertias.append(km.inertia_)
plt.plot(k_range, inertias, marker='o', color='#F6A01D')
plt.axvline(x=4, color='red', linestyle='--', label='Optimales k=4')
plt.xlabel('Anzahl Cluster k')
plt.ylabel('Inertia (SSE)')
plt.title('Elbow-Methode zur Bestimmung von k')
plt.legend()
plt.tight_layout()
plt.show()
6.2 Silhouette-Analyse
Der Silhouette Score misst, wie gut jeder Punkt zu seinem Cluster passt:
s(i) = (b(i) - a(i)) / max(a(i), b(i))
a(i) = mittlere Distanz zu Punkten im eigenen Cluster
b(i) = mittlere Distanz zu Punkten im nächsten Cluster
s(i) ≈ +1: Punkt liegt gut im Clusters(i) ≈ 0: Punkt liegt an der Grenze zweier Clusters(i) ≈ -1: Punkt liegt wahrscheinlich im falschen Cluster
from sklearn.metrics import silhouette_score, silhouette_samples
import numpy as np
scores = []
for k in range(2, 8):
km = KMeans(n_clusters=k, n_init=10, random_state=42)
labels = km.fit_predict(X)
scores.append(silhouette_score(X, labels))
print(f"k={k}: Silhouette Score = {scores[-1]:.3f}")
best_k = range(2, 8)[np.argmax(scores)]
print(f"\nBestes k: {best_k}")
7. Dimensionsreduktion – Grundkonzepte
Reale Datensätze haben oft Hunderte oder Tausende von Features (hohe Dimensionalität). Das verursacht mehrere Probleme:
Der Fluch der Dimensionalität
- Datenmangel: Im hochdimensionalen Raum wird der Datensatz sehr dünn
- Distanzmaße versagen: Alle Punkte werden ähnlich weit voneinander entfernt
- Overfitting: Modelle lernen Rauschen statt echte Muster
- Visualisierung: Ab 4 Dimensionen nicht mehr direkt darstellbar
Ziele der Dimensionsreduktion
Viele Features (z.B. 100)
│
▼
Dimensionsreduktion
│
▼
Wenige Features (z.B. 2–3)
Dabei soll möglichst viel Information erhalten bleiben!
Anwendungen:
- Daten visualisieren (2D/3D)
- Rauschen entfernen (Denoising)
- Trainingszeit reduzieren
- Multikollinearität beseitigen (korrelierte Features zusammenfassen)
8. Algorithmus: PCA – Principal Component Analysis
8.1 Grundidee
PCA sucht die Richtungen im Datensatz, in denen die größte Varianz liegt – diese Richtungen heißen Hauptkomponenten (Principal Components). Die Daten werden dann auf diese Richtungen projiziert.
Intuition: Stell dir eine Wolke von Punkten im 3D-Raum vor, die eigentlich auf einer Ebene liegt. PCA findet diese Ebene und projiziert alle Punkte hinein – 3D wird zu 2D, ohne viel Information zu verlieren.
8.2 Mathematischer Hintergrund
- Zentrieren: Mittelwert von X abziehen
- Kovarianzmatrix berechnen:
C = (1/n) · Xᵀ · X - Eigenwertzerlegung: Eigenvektoren = Hauptkomponenten, Eigenwerte = erklärte Varianz
- Projektion: Daten auf die k wichtigsten Hauptkomponenten projizieren
8.3 Erklärte Varianz
Ein zentrales Konzept: Wie viel Prozent der ursprünglichen Information bleiben erhalten?
import numpy as np
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
# Zifferndatensatz: 1797 Bilder, 64 Features (8×8 Pixel)
digits = load_digits()
X = StandardScaler().fit_transform(digits.data)
# PCA – alle Komponenten berechnen
pca_full = PCA()
pca_full.fit(X)
# Erklärte Varianz pro Komponente und kumulativ
explained = pca_full.explained_variance_ratio_
cumulative = np.cumsum(explained)
plt.figure(figsize=(9, 4))
plt.subplot(1, 2, 1)
plt.bar(range(1, 21), explained[:20], color='#F6A01D')
plt.xlabel('Komponente')
plt.ylabel('Erklärte Varianz')
plt.title('Varianz pro Komponente')
plt.subplot(1, 2, 2)
plt.plot(range(1, len(cumulative)+1), cumulative, color='#F6A01D', marker='.')
plt.axhline(y=0.95, color='red', linestyle='--', label='95% Varianz')
plt.xlabel('Anzahl Komponenten')
plt.ylabel('Kumulierte erklärte Varianz')
plt.title('Kumulierte Varianz')
plt.legend()
plt.tight_layout()
plt.show()
# Wie viele Komponenten für 95%?
n_95 = np.argmax(cumulative >= 0.95) + 1
print(f"Komponenten für 95% Varianz: {n_95} (statt 64)")
8.4 PCA zur Visualisierung
# Reduktion auf 2 Komponenten für Visualisierung
pca_2d = PCA(n_components=2)
X_2d = pca_2d.fit_transform(X)
plt.figure(figsize=(8, 6))
scatter = plt.scatter(X_2d[:, 0], X_2d[:, 1],
c=digits.target, cmap='tab10', alpha=0.6, s=20)
plt.colorbar(scatter, label='Ziffer')
plt.xlabel(f'PC1 ({pca_2d.explained_variance_ratio_[0]:.1%} Varianz)')
plt.ylabel(f'PC2 ({pca_2d.explained_variance_ratio_[1]:.1%} Varianz)')
plt.title('Zifferndatensatz – PCA auf 2 Komponenten')
plt.tight_layout()
plt.show()
8.5 PCA als Preprocessing
PCA kann vor einem Klassifikations-Algorithmus eingesetzt werden, um die Dimensionalität zu reduzieren:
from sklearn.pipeline import Pipeline
from sklearn.decomposition import PCA
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_digits
digits = load_digits()
X, y = digits.data, digits.target
# Pipeline: Skalierung → PCA → kNN
pipeline = Pipeline([
('scaler', StandardScaler()),
('pca', PCA(n_components=30)), # 64 → 30 Features
('knn', KNeighborsClassifier(n_neighbors=5))
])
scores = cross_val_score(pipeline, X, y, cv=5)
print(f"CV Accuracy mit PCA (30 Komp.): {scores.mean():.2%}")
# Vergleich ohne PCA
pipeline_nopca = Pipeline([
('scaler', StandardScaler()),
('knn', KNeighborsClassifier(n_neighbors=5))
])
scores_nopca = cross_val_score(pipeline_nopca, X, y, cv=5)
print(f"CV Accuracy ohne PCA (64 Feat): {scores_nopca.mean():.2%}")
8.6 Stärken und Schwächen
| ✅ Stärken | ❌ Schwächen |
|---|---|
| Rauschen wird reduziert | Komponenten schwer interpretierbar |
| Korrelierte Features werden kombiniert | Nur lineare Zusammenhänge |
| Schnell und deterministisch | Informationsverlust unvermeidbar |
| Gut als Preprocessing-Schritt | Skalierung zwingend notwendig |
9. Algorithmus: t-SNE
9.1 Grundidee
t-SNE (t-distributed Stochastic Neighbor Embedding) ist eine nichtlineare Dimensionsreduktionsmethode, die speziell für die Visualisierung hochdimensionaler Daten entwickelt wurde. Im Gegensatz zu PCA versucht t-SNE, die lokale Struktur (Nachbarschaften) zu erhalten.
Achtung: t-SNE ist ausschließlich zur Visualisierung geeignet, nicht als Preprocessing für nachgelagerte Algorithmen!
9.2 Implementierung
from sklearn.manifold import TSNE
from sklearn.datasets import load_digits
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
digits = load_digits()
X = StandardScaler().fit_transform(digits.data)
# t-SNE (dauert etwas länger als PCA)
tsne = TSNE(n_components=2, perplexity=30, n_iter=1000, random_state=42)
X_tsne = tsne.fit_transform(X)
plt.figure(figsize=(9, 7))
scatter = plt.scatter(X_tsne[:, 0], X_tsne[:, 1],
c=digits.target, cmap='tab10', alpha=0.7, s=20)
plt.colorbar(scatter, label='Ziffer')
plt.title('Zifferndatensatz – t-SNE Visualisierung')
plt.xlabel('t-SNE Dimension 1')
plt.ylabel('t-SNE Dimension 2')
plt.tight_layout()
plt.show()
9.3 PCA vs. t-SNE
| PCA | t-SNE | |
|---|---|---|
| Methode | Linear | Nichtlinear |
| Geschwindigkeit | Sehr schnell | Langsam |
| Ziel | Maximale Varianz erhalten | Lokale Struktur erhalten |
| Reproduzierbar | ✅ Ja | ⚠️ Nur mit random_state |
| Als Preprocessing | ✅ Ja | ❌ Nein |
| Für Visualisierung | Gut | Sehr gut |
| Großer Datensatz | ✅ Ja | ⚠️ Begrenzt (< 10.000) |
Tipp: Bei großen Datensätzen erst mit PCA auf 50 Komponenten reduzieren, dann t-SNE anwenden – das spart deutlich Rechenzeit.
# Empfohlene Kombination für große Datensätze:
pca_pre = PCA(n_components=50)
X_pca = pca_pre.fit_transform(X)
X_tsne = TSNE(n_components=2, random_state=42).fit_transform(X_pca)
10. Anwendungsbeispiel: Kundensegmentierung
10.1 Aufgabenstellung
Ein Online-Shop möchte seine Kunden anhand ihres Kaufverhaltens in Segmente einteilen, um gezielte Marketingmaßnahmen durchzuführen.
10.2 Vollständige Pipeline
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.metrics import silhouette_score
# ── 1. Synthetische Kundendaten erstellen ─────────────────────────────────
np.random.seed(42)
n = 400
# Drei Kundengruppen simulieren
gruppen = {
'Gelegenheitskäufer': {'n': 150, 'ausgaben': (20, 10), 'besuche': (2, 1)},
'Stammkunden': {'n': 150, 'ausgaben': (80, 20), 'besuche': (8, 2)},
'Premium-Kunden': {'n': 100, 'ausgaben': (200, 40), 'besuche': (5, 1)},
}
dfs = []
for name, params in gruppen.items():
n_g = params['n']
df_g = pd.DataFrame({
'monatliche_ausgaben': np.random.normal(*params['ausgaben'], n_g).clip(5),
'besuche_pro_monat': np.random.normal(*params['besuche'], n_g).clip(1),
'kundenzufriedenheit': np.random.uniform(2, 5, n_g).round(1),
'tage_seit_letztkauf': np.random.exponential(15, n_g).clip(1, 90).astype(int),
})
dfs.append(df_g)
kunden = pd.concat(dfs, ignore_index=True).sample(frac=1, random_state=42)
print(kunden.describe().round(2))
# ── 2. Preprocessing ──────────────────────────────────────────────────────
X = kunden.values
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# ── 3. Optimales k bestimmen (Elbow + Silhouette) ─────────────────────────
inertias, silhouettes = [], []
k_range = range(2, 9)
for k in k_range:
km = KMeans(n_clusters=k, n_init=10, random_state=42)
labels = km.fit_predict(X_scaled)
inertias.append(km.inertia_)
silhouettes.append(silhouette_score(X_scaled, labels))
fig, axes = plt.subplots(1, 2, figsize=(11, 4))
axes[0].plot(k_range, inertias, marker='o', color='#F6A01D')
axes[0].set_title('Elbow-Methode'); axes[0].set_xlabel('k'); axes[0].set_ylabel('Inertia')
axes[1].plot(k_range, silhouettes, marker='o', color='#F6A01D')
axes[1].set_title('Silhouette Score'); axes[1].set_xlabel('k'); axes[1].set_ylabel('Score')
plt.tight_layout(); plt.show()
# ── 4. K-Means mit k=3 ────────────────────────────────────────────────────
kmeans = KMeans(n_clusters=3, n_init=10, random_state=42)
kunden['segment'] = kmeans.fit_predict(X_scaled)
# ── 5. Segmente analysieren ───────────────────────────────────────────────
print("\nSegment-Profile:")
print(kunden.groupby('segment').mean().round(2))
# ── 6. Visualisierung mit PCA ─────────────────────────────────────────────
pca = PCA(n_components=2)
X_2d = pca.fit_transform(X_scaled)
plt.figure(figsize=(8, 6))
for seg in sorted(kunden['segment'].unique()):
mask = kunden['segment'] == seg
plt.scatter(X_2d[mask, 0], X_2d[mask, 1], label=f'Segment {seg}', alpha=0.6, s=40)
# Centroids im PCA-Raum einzeichnen
centroids_2d = pca.transform(kmeans.cluster_centers_)
plt.scatter(centroids_2d[:, 0], centroids_2d[:, 1],
c='black', marker='X', s=200, zorder=5, label='Centroids')
plt.xlabel(f'PC1 ({pca.explained_variance_ratio_[0]:.1%})')
plt.ylabel(f'PC2 ({pca.explained_variance_ratio_[1]:.1%})')
plt.title('Kundensegmentierung – K-Means (k=3) visualisiert mit PCA')
plt.legend(); plt.tight_layout(); plt.show()
11. Vergleich der Algorithmen
Clustering-Algorithmen
| K-Means | DBSCAN | Hierarchisch | |
|---|---|---|---|
| k vorab nötig | ✅ Ja | ❌ Nein | ❌ Nein (Schnitt wählen) |
| Clusterform | Nur kugelförmig | Beliebig | Beliebig |
| Ausreißer | Werden zugewiesen | Werden erkannt | Werden zugewiesen |
| Geschwindigkeit | Schnell | Mittel | Langsam (bei großen n) |
| Skalierbarkeit | Sehr gut | Gut | Schlecht |
| Einfache Parameter | ✅ | ❌ (eps schwer) | ✅ |
| Wann einsetzen | Kompakte Cluster, große Daten | Unbekannte Formen, Ausreißer | Explorative Analyse, kleines n |
Dimensionsreduktionsmethoden
| PCA | t-SNE | |
|---|---|---|
| Typ | Linear | Nichtlinear |
| Hauptzweck | Preprocessing + Visualisierung | Nur Visualisierung |
| Geschwindigkeit | Sehr schnell | Langsam |
| Neue Datenpunkte transformierbar | ✅ | ❌ |
| Interpretierbarkeit | Mittel (Varianzanteil) | Gering |
| Wann einsetzen | Immer als erster Schritt | Finale Visualisierung |
12. Zusammenfassung und Ausblick
Überblick
Unsupervised Learning
│
├── Clustering
│ ├── K-Means → schnell, kompakte Cluster, k vorab nötig
│ ├── DBSCAN → beliebige Formen, Ausreißer, kein k nötig
│ └── Hierarchisch → Dendrogram, explorativ, langsam
│
└── Dimensionsreduktion
├── PCA → linear, schnell, Preprocessing + Visualisierung
└── t-SNE → nichtlinear, langsam, nur Visualisierung
Entscheidungshilfe
Clustering oder Dimensionsreduktion?
→ Daten gruppieren: Clustering
→ Daten visualisieren/vereinf.: Dimensionsreduktion
Welcher Clustering-Algorithmus?
→ Ich weiß, wie viele Cluster: K-Means
→ Unbekannte Clusterform: DBSCAN
→ Explorative Analyse: Hierarchisch
Welche Dimensionsreduktion?
→ Als Preprocessing: PCA
→ Nur Visualisierung: t-SNE (ggf. nach PCA)
Checkliste
✅ Features vor Clustering/PCA immer skalieren (StandardScaler)
✅ Clusteranzahl mit Elbow + Silhouette bestimmen
✅ Ergebnis immer visualisieren (PCA oder t-SNE)
✅ Cluster inhaltlich interpretieren (Mittelwerte pro Cluster)
✅ PCA: erklärte Varianz prüfen (Ziel: 90–95%)
✅ t-SNE nur zur Visualisierung, nicht als Preprocessing
Ausblick: Nächste Themen
- Deep Learning: Neuronale Netze, Backpropagation, Aktivierungsfunktionen
- Convolutional Neural Networks (CNNs): Bilderkennung
- Natural Language Processing: Textklassifikation, Transformer-Modelle
- MLOps: Modelle versionieren, deployen und überwachen
Anhang: Schnellreferenz
# ── Clustering ────────────────────────────────────────────────────────────
from sklearn.cluster import KMeans, DBSCAN, AgglomerativeClustering
km = KMeans(n_clusters=3, n_init=10, random_state=42)
db = DBSCAN(eps=0.5, min_samples=5)
hc = AgglomerativeClustering(n_clusters=3, linkage='ward')
labels = km.fit_predict(X_scaled) # Für alle drei gleich
# ── Bewertung ─────────────────────────────────────────────────────────────
from sklearn.metrics import silhouette_score, davies_bouldin_score
sil = silhouette_score(X_scaled, labels) # höher = besser
db_score = davies_bouldin_score(X_scaled, labels) # niedriger = besser
# ── Dimensionsreduktion ───────────────────────────────────────────────────
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
print(pca.explained_variance_ratio_) # Varianzanteil je Komponente
tsne = TSNE(n_components=2, perplexity=30, random_state=42)
X_tsne = tsne.fit_transform(X_scaled) # Nur fit_transform, kein transform!
# ── Dendrogram ────────────────────────────────────────────────────────────
from scipy.cluster.hierarchy import dendrogram, linkage
linked = linkage(X_scaled, method='ward')
dendrogram(linked)
HTL Pinkafeld – IF/IT | Data Science & AI | 12. Schulstufe