import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.metrics import silhouette_score, davies_bouldin_score # ========================================================= # ?? EINSTELLUNGEN # ========================================================= RANDOM_SEED = 42 MAX_K = 8 POINTS_PER_CLUSTER = 100 # echte Cluster (für Simulation) CENTER_1 = [0, 0] CENTER_2 = [6, 6] CENTER_3 = [0, 6] # ========================================================= # 1. DATEN GENERIEREN # ========================================================= np.random.seed(RANDOM_SEED) data1 = np.random.randn(POINTS_PER_CLUSTER, 2) + CENTER_1 data2 = np.random.randn(POINTS_PER_CLUSTER, 2) + CENTER_2 data3 = np.random.randn(POINTS_PER_CLUSTER, 2) + CENTER_3 X = np.vstack((data1, data2, data3)) # ========================================================= # 2. ELBOW + GÜTEMASSE # ========================================================= k_values = range(1, MAX_K + 1) inertia_values = [] silhouette_values = [] db_values = [] for k in k_values: kmeans = KMeans(n_clusters=k, random_state=RANDOM_SEED, n_init=10) kmeans.fit(X) inertia_values.append(kmeans.inertia_) if k >= 2: labels = kmeans.labels_ silhouette_values.append(silhouette_score(X, labels)) db_values.append(davies_bouldin_score(X, labels)) else: silhouette_values.append(np.nan) db_values.append(np.nan) # ========================================================= # 3. BESTES k (vereinfacht: nach Silhouette) # ========================================================= best_k = k_values[np.nanargmax(silhouette_values)] # Frage: # Warum nehmen wir hier Silhouette und nicht Inertia? # Lösung: # ? Inertia sinkt immer ? kein klares Optimum # ========================================================= # 4. FINALES MODELL # ========================================================= kmeans_final = KMeans(n_clusters=best_k, random_state=RANDOM_SEED, n_init=10) kmeans_final.fit(X) labels_final = kmeans_final.labels_ centers_final = kmeans_final.cluster_centers_ # ========================================================= # 5. VISUALISIERUNG # ========================================================= fig, ax = plt.subplots(1, 4, figsize=(20, 4)) # ---- Originaldaten ---- ax[0].scatter(X[:, 0], X[:, 1]) ax[0].set_title("Rohdaten (unclustered)") # Frage: # Siehst du hier schon Cluster? # Lösung: # ? Ja, visuell oft erkennbar, aber nicht immer eindeutig # ---- Elbow ---- ax[1].plot(k_values, inertia_values, marker='o') ax[1].set_title("Elbow (Inertia)") ax[1].set_xlabel("k") ax[1].set_ylabel("Fehler") # ---- Silhouette ---- ax[2].plot(k_values, silhouette_values, marker='o') ax[2].set_title("Silhouette Score") ax[2].set_xlabel("k") # ---- Finales Clustering ---- scatter = ax[3].scatter(X[:, 0], X[:, 1], c=labels_final) ax[3].scatter(centers_final[:, 0], centers_final[:, 1], c='red', s=200, marker='X') ax[3].set_title(f"K-Means Ergebnis (k={best_k})") # Frage: # Warum sind die Cluster farbig getrennt? # Lösung: # ? Hard Clustering: jeder Punkt genau ein Label plt.tight_layout() plt.show() # ========================================================= # ? WEITERE FRAGEN # ========================================================= # Frage: # Was passiert, wenn wir die Daten stärker überlappen lassen? # Lösung: # ? Clustering wird schwieriger, Scores schlechter # Frage: # Warum können verschiedene Runs unterschiedliche Ergebnisse liefern? # Lösung: # ? zufällige Initialisierung der Zentren # Frage: # Ist das gefundene k immer korrekt? # Lösung: # ? Nein, nur heuristisch bestimmt