# CAS PML – Unsupervised Learning: Clustering-Aufgaben > Modul: CAS Practical Machine Learning – Unsupervised Learning (Dehmer) > Inhalt: die zwei Clustering-Übungen aus dem Skript, plus ein Elbow-Demo ## Projektstruktur ``` . ├── data/ │ ├── data_delivery_fleet.tsv # Übung 1 │ └── data_stocks.tsv # Übung 2 (Dateiname ggf. anpassen) ├── plots/ # generierte PNGs (headless) ├── src/ │ ├── uebung1_kmeans_fleet.py # Übung 1: k-Means (Lösung, lauffähig) │ ├── uebung2_kprototypes_stocks.py # Übung 2: k-Prototypes (Codegerüst, TODOs) │ └── k_means2_elbow_measures.py # Zusatz: Elbow & Gütemasse (synthetisch) ├── devenv.nix └── README.md ``` ## Setup & Ausführen In der devenv-Shell: ``` python src/uebung1_kmeans_fleet.py python src/uebung2_kprototypes_stocks.py python src/k_means2_elbow_measures.py ``` Für Übung 2 wird das Paket **`kmodes`** benötigt (k-Prototypes ist nicht in scikit-learn). In `devenv.nix` zu den `venv.requirements` hinzufügen: ``` kmodes ``` Alle Skripte laufen **headless**: Plots werden als PNG nach `plots/` geschrieben (kein `plt.show()`, da in der Shell kein Display – Agg-Backend). ## Gütemasse zur Wahl von $k$ (gemeinsame Referenz) - Inertia / WCSS (k-Means) bzw. `cost_` (k-Prototypes) – Summe der Abstände/Unähnlichkeiten zum Zentrum; sinkt monoton mit $k$, daher nur "Knick" (Elbow) $$ \text{WCSS} = \sum_{i=1}^{k} \sum_{x \in P_i} \lVert x - \mu_i \rVert^2 $$ - Erklärte Varianz – Anteil der Between-Cluster-Varianz an der Gesamtvarianz, höher = besser (ideal 100 %) $$ \text{Variance Explained} = \frac{\text{BSS}}{\text{TSS}} \cdot 100\,\% $$ - Silhouette-Score – $a_i$ = mittlere Intra-, $b_i$ = mittlere nächste Inter-Cluster-Distanz; Bereich $[-1, 1]$, höher = besser $$ s_i = \frac{b_i - a_i}{\max(a_i, b_i)} $$ - Davies-Bouldin (nur Zusatz-Demo) – niedriger = besser (Achtung: umgekehrt zur Silhouette) $$ DB = \frac{1}{k} \sum_{i=1}^{k} \max_{j \neq i} \frac{\sigma_i + \sigma_j}{d(c_i, c_j)} $$ --- ## Übung 1 — k-Means: Delivery Fleet Aufgabenstellung (Skript): Fleet-Daten von Lieferfahrer:innen clustern. 1. Datensatz aus tab-separiertem File laden (Pandas) 2. Daten visualisieren und eine sinnvolle Clusterzahl visuell *und* systematisch finden 3. Daten clustern Datensatz `data_delivery_fleet.tsv` (3 Spalten): - `Driver_ID` – ID der Fahrer:in - `Distance_Feature` – mittlere gefahrene Meilen pro Tag - `Speeding_Feature` – % der Zeit über dem Tempolimit (>5 mph) Geclustert wird auf `Distance_Feature` × `Speeding_Feature`. Ablauf von `uebung1_kmeans_fleet.py` (PNGs in `plots/`): 1. Rohdaten-Scatter (`01_rohdaten.png`) 2. K-Means mit frei gewähltem $k=4$ (`02_kmeans_k4.png`) 3. Sweep $k = 1 \dots 8$ als Übersichts-Grid (`03_kmeans_sweep_k1-8.png`) 4. $k$ über Inertia/Elbow (`04`), erklärte Varianz (`05`), Silhouette (`06`) 5. finales Modell mit bestem $k$ (`07_final.png`) Status: **fertige Lösung** (aus dem Notebook umgebaut, lauffähig). > Anpassungen ggü. Notebook: `.as_matrix()` → `.to_numpy()`; `plt.show()` → `savefig`; Hartigan als optionaler Legacy-Block (`RUN_HARTIGAN = False`). --- ## Übung 2 — k-Prototypes: Stock Data Aufgabenstellung (Skript): einen grösseren Stock-Datensatz clustern. 1. Datensatz (tab-separiert) laden 2. Daten clustern Warum k-Prototypes? Die Daten sind **gemischt** (numerisch + kategorial): - k-Means → nur numerisch - k-Modes → nur kategorial (Modus statt Mittel, Mismatch-Distanz) - k-Prototypes = beides kombiniert, gewichtet über $\gamma$ $$ D(x, c) = \underbrace{\sum_{\text{num}} (x_j - c_j)^2}_{\text{numerisch (L2)}} + \gamma \underbrace{\sum_{\text{cat}} \delta(x_j, c_j)}_{\text{kategorial (Mismatches)}} $$ API-Kern (`kmodes`): ```python from kmodes.kprototypes import KPrototypes kp = KPrototypes(n_clusters=k, init="Cao", random_state=0, n_init=5) labels = kp.fit_predict(X, categorical=[]) kp.cost_ # Elbow-Analogon zur Inertia kp.cluster_centroids_ # numerisch = Mittel, kategorial = Modus ``` Gerüst-Abschnitte in `uebung2_kprototypes_stocks.py` (mit TODO selbst füllen): 1. Daten laden & verstehen (dtypes → numerisch vs. kategorial, ID-Spalte raus?) 2. Features vorbereiten: $X$ bauen + `categorical_idx` setzen 3. $k$ finden: Elbow über `cost_` 4. finales Clustering fitten 5. Interpretation: Cluster je Feature beschreiben, semantisch deuten Status: **Codegerüst** – Boilerplate (Imports/Pfade/Plots) gesetzt, Implementierung offen. --- ## Zusatz — Elbow-Methode & Gütemasse (synthetisch) Kein Skript-Auftrag, sondern ein Demo zur $k$-Wahl auf synthetischen Daten (drei Gauss-Blobs). Vergleicht Inertia (Elbow), Silhouette und Davies-Bouldin. Ablauf von `k_means2_elbow_measures.py` (4-Panel-Plot): 1. Daten generieren: je 100 Punkte um $(0,0)$, $(6,6)$, $(0,6)$ (Seed fix) 2. Für $k = 1 \dots 8$ K-Means fitten und Inertia, Silhouette, Davies-Bouldin sammeln 3. Bestes $k$ wählen (vereinfacht: max. Silhouette) 4. Finales Modell + Visualisierung (Rohdaten | Elbow | Silhouette | Ergebnis) Verständnisfragen / Experimente: - [ ] Warum zur $k$-Wahl Silhouette statt Inertia? - [ ] Daten stärker überlappen lassen → wie verändern sich die Scores? - [ ] Davies-Bouldin statt Silhouette als Kriterium (dann `argmin`!) → dasselbe $k$?