W3docs

K-means

K-Means-Clustering in Python mit scikit-learn: Algorithmus, Feature-Skalierung, K-Wahl, Silhouette-Score und häufige Fehler.

K-Means ist ein unüberwachter Machine-Learning-Algorithmus, der einen Datensatz in K nicht überlappende Cluster aufteilt, indem er die gesamte quadrierte Distanz zwischen jedem Datenpunkt und dem ihm zugewiesenen Cluster-Zentroid minimiert. Diese Seite erklärt, wie der Algorithmus funktioniert, wie man ihn in Python mit scikit-learn implementiert, wie man die richtige Anzahl von Clustern wählt und welche wichtigen Fallstricke es zu vermeiden gilt.

Was ist K-Means-Clustering?

K-Means gruppiert Datenpunkte so, dass Punkte innerhalb desselben Clusters möglichst ähnlich sind, während Punkte in verschiedenen Clustern möglichst unterschiedlich sind. „Ähnlichkeit" wird durch die euklidische Distanz gemessen — den geraden Abstand zwischen zwei Punkten im Feature-Raum.

Da K-Means mit rohen Distanzwerten arbeitet, ist es ein unüberwachter Algorithmus: Er entdeckt Strukturen in unbeschrifteten Daten, ohne eine Zielvariable zu benötigen.

Typische Anwendungsfälle in der Praxis:

  • Kundensegmentierung — Kunden nach Kaufverhalten und demografischen Merkmalen gruppieren.
  • Bildkomprimierung — Farben reduzieren, indem jedes Pixel durch die Farbe seines nächsten Zentroids ersetzt wird.
  • Dokumenten-Clustering — Nachrichtenartikel oder Support-Tickets nach Thema gruppieren.
  • Anomalieerkennung — Punkte, die weit von jedem Zentroid entfernt sind, können Ausreißer sein.

Funktionsweise des Algorithmus

K-Means wechselt zwischen zwei Schritten, bis sich die Cluster-Zuweisungen nicht mehr ändern (Konvergenz):

  1. Initialisieren — K anfängliche Zentroide (Startpunkte) auswählen. Die Standard-Strategie k-means++ verteilt sie räumlich, um schlechte Initialisierungen zu vermeiden.
  2. Zuweisen — jeden Datenpunkt dem nächsten Zentroid zuweisen, wodurch K Cluster entstehen.
  3. Aktualisieren — jeden Zentroid als den Mittelwert aller ihm zugewiesenen Punkte neu berechnen.
  4. Wiederholen der Schritte 2–3, bis kein Punkt mehr den Cluster wechselt oder eine maximale Anzahl von Iterationen erreicht ist.

Die zu minimierende Größe heißt Inertia (auch als WCSS — Within-Cluster Sum of Squares — bezeichnet):

inertia = sum over all points of (distance from point to its centroid)²

Niedrigere Inertia bedeutet engere, kompaktere Cluster.

k-means++-Initialisierung

Das Standard-init='k-means++' (scikit-learns Standard) wählt den ersten Zentroid zufällig aus und wählt dann jeden weiteren Zentroid mit einer Wahrscheinlichkeit proportional zur quadrierten Distanz zum nächsten bereits gewählten Zentroid. Dies verteilt die anfänglichen Zentroide räumlich und findet typischerweise bessere Cluster schneller als eine rein zufällige Initialisierung.

Feature-Skalierung vor dem Clustering

K-Means basiert vollständig auf der euklidischen Distanz. Wenn ein Feature in Tausend gemessen wird (zum Beispiel Jahreseinkommen) und ein anderes in einstelligen Zahlen (zum Beispiel eine Bewertung von 1 bis 5), dominiert das Feature mit großen Werten die Distanzberechnung und das Feature mit kleinerem Wertebereich wird effektiv ignoriert. Skalieren Sie Ihre Features daher immer zuerst.

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

StandardScaler zentriert jedes Feature auf Mittelwert 0 und Standardabweichung 1. Alternativen wie MinMaxScaler finden Sie im Scale-Kapitel.

K-Means mit scikit-learn implementieren

Das folgende Beispiel generiert einen synthetischen Datensatz, skaliert ihn, passt K-Means an und untersucht die Ergebnisse.

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import numpy as np

# Generate 300 points in 3 natural clusters
X, y_true = make_blobs(n_samples=300, centers=3, random_state=42)

# Scale the features — always required before K-Means
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Fit K-Means with 3 clusters
kmeans = KMeans(n_clusters=3, init='k-means++', n_init=10, random_state=42)
kmeans.fit(X_scaled)

# Cluster assignment for every training point (0-indexed)
labels = kmeans.labels_
print('Cluster labels (first 10):', labels[:10])
# e.g. [2 2 0 1 0 1 2 2 0 1]

print('Cluster sizes:', np.bincount(labels))
# e.g. [100 100 100]

print('Inertia (WCSS):', round(kmeans.inertia_, 2))
# e.g. 18.26

print('Iterations to converge:', kmeans.n_iter_)
# e.g. 2

Wichtige Attribute nach dem Anpassen:

AttributBeschreibung
labels_Cluster-ID (0 bis K-1) für jeden Trainingspunkt
cluster_centers_Koordinaten der K Zentroide (Form: K × n_features)
inertia_Gesamtes WCSS — niedriger ist besser
n_iter_Anzahl der EM-Iterationen bis zur Konvergenz

Cluster-Zugehörigkeit für neue Daten vorhersagen

Nachdem der Scaler und das Modell auf Trainingsdaten angepasst wurden, verwenden Sie scaler.transform() + kmeans.predict(), um neue Punkte bestehenden Clustern zuzuweisen. Passen Sie den Scaler niemals erneut an neue Daten an.

import numpy as np

# Two new, unseen points (original feature scale)
new_points = np.array([[0.5, -0.5],
                        [-1.0,  2.0]])

# Transform with the SAME scaler used during training
new_scaled = scaler.transform(new_points)

# Predict cluster membership
predictions = kmeans.predict(new_scaled)
print('Predicted clusters:', predictions)
# e.g. [2 0]

Die richtige Anzahl von Clustern wählen (K)

K-Means erfordert, dass Sie K im Voraus angeben, was oft der schwierigste Teil ist. Zwei komplementäre Techniken helfen dabei: die Elbow-Methode und der Silhouette-Score.

Die Elbow-Methode

Tragen Sie die Inertia (WCSS) gegen K auf. Je größer K wird, desto geringer wird die Inertia — aber die Verbesserungsrate verlangsamt sich. Der „Ellbogen" ist der Punkt, an dem das Hinzufügen eines weiteren Clusters nur noch geringe Verbesserungen bringt.

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

X, _ = make_blobs(n_samples=300, centers=3, random_state=42)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

wcss = []
for k in range(1, 11):
    km = KMeans(n_clusters=k, n_init=10, random_state=42)
    km.fit(X_scaled)
    wcss.append(km.inertia_)

plt.plot(range(1, 11), wcss, marker='o')
plt.xlabel('Number of clusters (K)')
plt.ylabel('Inertia (WCSS)')
plt.title('Elbow method')
plt.tight_layout()
plt.show()

Bei diesem Datensatz (3 natürliche Cluster) fällt die Inertia von K=1 bis K=3 steil ab und flacht dann ab. Der Ellbogen bei K=3 bestätigt die tatsächliche Anzahl der Cluster.

Der Silhouette-Score

Der Silhouette-Score misst, wie gut jeder Punkt zu seinem eigenen Cluster passt im Vergleich zum nächstgelegenen benachbarten Cluster. Er reicht von -1 (falscher Cluster) bis +1 (perfekt getrennter Cluster). Ein Score über 0,5 ist im Allgemeinen gut; über 0,7 ist stark.

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import silhouette_score

X, _ = make_blobs(n_samples=300, centers=3, random_state=42)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

for k in range(2, 8):
    km = KMeans(n_clusters=k, n_init=10, random_state=42)
    labels = km.fit_predict(X_scaled)
    score = silhouette_score(X_scaled, labels)
    print(f'k={k}  silhouette={score:.3f}')

Ausgabe:

k=2  silhouette=0.688
k=3  silhouette=0.848
k=4  silhouette=0.679
k=5  silhouette=0.522
k=6  silhouette=0.357
k=7  silhouette=0.371

K=3 erzeugt den höchsten Silhouette-Score (0,848) und bestätigt, dass drei Cluster diese Daten am besten beschreiben. Verwenden Sie beide Methoden zusammen — das Elbow-Diagramm zeigt, wo die Verbesserung stagniert; der Silhouette-Score liefert eine einzelne Zahl zum Vergleich verschiedener K-Werte.

K-Means-Cluster visualisieren

Streudiagramme zeigen, ob die Cluster gut voneinander getrennt sind. Bei Datensätzen mit mehr als zwei Features würde man zunächst eine Dimensionsreduktion (z. B. PCA) anwenden, bevor man sie darstellt.

from sklearn.cluster import KMeans
from sklearn.datasets import make_blobs
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt

X, _ = make_blobs(n_samples=300, centers=3, random_state=42)
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

kmeans = KMeans(n_clusters=3, n_init=10, random_state=42)
labels = kmeans.fit_predict(X_scaled)
centers = kmeans.cluster_centers_

plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=labels, cmap='viridis', s=40, alpha=0.7)
plt.scatter(centers[:, 0], centers[:, 1],
            c='red', marker='X', s=200, zorder=5, label='Centroids')
plt.legend()
plt.title('K-Means clustering (k=3)')
plt.xlabel('Feature 1 (scaled)')
plt.ylabel('Feature 2 (scaled)')
plt.tight_layout()
plt.show()

Jede Farbe repräsentiert einen Cluster. Rote Kreuze markieren die Zentroide — die durchschnittliche Position aller Punkte in diesem Cluster.

Vorteile und Einschränkungen

Vorteile

  • Einfach und schnell. K-Means ist O(n · k · i), wobei n die Anzahl der Punkte, k die Anzahl der Cluster und i die Anzahl der Iterationen ist. Mit MiniBatchKMeans skaliert er auf Millionen von Datenpunkten.
  • Leicht zu interpretieren. Zentroide liefern eine konkrete Zusammenfassung der typischen Werte jedes Clusters.
  • Funktioniert gut, wenn Cluster ungefähr kugelförmig und gleich groß sind.
  • Keine Beschriftung der Daten erforderlich. Vollständig unüberwacht — keine Zielvariable nötig.

Einschränkungen

  • K muss im Voraus angegeben werden. Nutzen Sie die Elbow-Methode und den Silhouette-Score als Orientierung, aber keine der Methoden gibt eine eindeutige Antwort für mehrdeutige Daten.
  • Empfindlich gegenüber der Initialisierung. Eine schlechte Startkonfiguration kann zu einem lokalen Optimum konvergieren. k-means++ und mehrfache Neustarts (n_init=10) reduzieren dieses Risiko.
  • Setzt kugelförmige, gleich große Cluster voraus. K-Means hat Schwierigkeiten mit länglichen, halbmondförmigen oder sehr ungleich großen Clustern. Verwenden Sie Hierarchisches Clustering oder DBSCAN für nicht-kugelförmige Formen.
  • Empfindlich gegenüber Ausreißern. Ein einzelner extremer Punkt kann einen Zentroid weit vom tatsächlichen Cluster-Zentrum wegziehen. Entfernen oder begrenzen Sie Ausreißer vor dem Anpassen.
  • Skalierungsempfindlich. Features mit unterschiedlichen Skalen müssen standardisiert werden — siehe das Scale-Kapitel.

Häufige Fallstricke

Feature-Skalierung überspringen. Dies ist der bei weitem häufigste Fehler. Ohne Skalierung dominieren Features mit großen numerischen Wertebereichen die Distanzberechnung, und Features mit kleinerem Wertebereich werden ignoriert.

n_init=1 setzen. Der Standard in älteren scikit-learn-Versionen war n_init='warn' (was eine Warnung ausgab, wenn man es nicht setzte). Setzen Sie immer n_init=10 (oder mehr), um K-Means mit 10 verschiedenen zufälligen Initialisierungen auszuführen und das beste Ergebnis zu behalten.

Den Scaler auf neuen Daten erneut anpassen. Passen Sie den StandardScaler einmal auf Ihre Trainingsdaten an, und rufen Sie dann transform() für neue Daten auf. Das erneute Aufrufen von fit_transform() auf neuen Daten ändert die Skalierung und macht das Modell inkonsistent.

Cluster-IDs als bedeutungsvolle Reihenfolge behandeln. Die Cluster-IDs (0, 1, 2, …) sind willkürliche Bezeichnungen, die von scikit-learn vergeben werden. Sie sind nicht ordinal — Cluster 2 ist nicht „größer" oder „wichtiger" als Cluster 0. Vergleichen Sie Cluster anhand ihrer Zentroid-Werte und Mitgliederzahlen.

K-Means auf nicht-numerischen Daten verwenden. K-Means benötigt numerische Features zur Distanzberechnung. Kodieren Sie kategoriale Daten zuerst (zum Beispiel mit One-Hot-Encoding) und überlegen Sie, ob die euklidische Distanz für Ihren Anwendungsfall noch sinnvoll ist. Siehe das Kapitel über kategoriale Daten.

K-Means vs. Hierarchisches Clustering

MerkmalK-MeansHierarchisches Clustering
Anzahl der ClusterMuss K vor der Ausführung angebenKann nach der Ausführung gewählt werden (Dendrogramm inspizieren)
SkalierbarkeitSkaliert auf Millionen von ZeilenO(n²) Speicher — unpraktisch ab ~10.000 Zeilen
DeterminismusZufällig (verwenden Sie random_state für Reproduzierbarkeit)Vollständig deterministisch
Cluster-FormenAm besten für kugelförmige ClusterFlexibel mit verschiedenen Linkage-Methoden
AusgabeFlache Cluster-ZuweisungenBaum (Dendrogramm) mit der Merge-Historie

Verwenden Sie K-Means, wenn Ihr Datensatz groß ist und Sie bereits eine gute Schätzung von K haben. Verwenden Sie Hierarchisches Clustering, wenn Sie mehrere K-Werte erkunden möchten, ohne das Modell neu anzupassen, oder wenn Cluster möglicherweise nicht kugelförmig sind.

Praktische Checkliste

Folgen Sie dieser Checkliste, wenn Sie K-Means auf einen neuen Datensatz anwenden:

  1. Ausreißer entfernen oder begrenzen — extreme Werte verzerren Zentroide.
  2. Kategoriale Variablen kodieren — K-Means erfordert numerische Eingaben.
  3. Features skalieren mit StandardScaler (oder MinMaxScaler, wenn die Feature-Verteilung begrenzt ist).
  4. Das Elbow-Diagramm verwenden, um Kandidatenwerte für K einzugrenzen.
  5. Den Silhouette-Score verwenden, um spezifische K-Werte quantitativ zu vergleichen.
  6. n_init=10 und init='k-means++' für eine robuste Initialisierung setzen.
  7. Cluster-Größen überprüfen mit np.bincount(labels) — sehr ungleiche Größen können auf ein schlechtes K oder Ausreißer-Kontaminierung hinweisen.
  8. Visualisieren mit einem Streudiagramm (oder PCA-Projektion für hochdimensionale Daten).

Verwandte Kapitel

Was this page helpful?