fix: encoding
This commit is contained in:
@@ -24,8 +24,6 @@ Ausführen (in der devenv-Shell):
|
|||||||
python src/k_means2_elbow_measures.py
|
python src/k_means2_elbow_measures.py
|
||||||
```
|
```
|
||||||
|
|
||||||
> Hinweis: Das erhaltene Textfile hat kaputte Umlaute (Windows-1252 statt UTF-8). Beim Übernehmen nach `src/` als UTF-8 neu speichern, sonst sind die Kommentare unleserlich.
|
|
||||||
|
|
||||||
## Ablauf des Skripts
|
## Ablauf des Skripts
|
||||||
|
|
||||||
1. Daten generieren: je 100 Punkte um die Zentren $(0,0)$, $(6,6)$, $(0,6)$ via `np.random.randn` (Seed fix → reproduzierbar)
|
1. Daten generieren: je 100 Punkte um die Zentren $(0,0)$, $(6,6)$, $(0,6)$ via `np.random.randn` (Seed fix → reproduzierbar)
|
||||||
|
|||||||
@@ -0,0 +1,131 @@
|
|||||||
|
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
|
||||||
|
|||||||
Reference in New Issue
Block a user