feature(workshop): add workshop8 solutions
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
# Workshop 08 — Standardisierung & Lineare Regression
|
||||
|
||||
> CAS Practical Machine Learning · Supervised Learning · Lektion 5 (Foliensatz 13, Folie 68)
|
||||
> Zeit: 60'
|
||||
|
||||
## Aufgabenstellung
|
||||
|
||||
Untersuche den Einfluss des **Standardisierens der Features** auf folgende Ergebnisse
|
||||
der Linearen Regression:
|
||||
|
||||
- Modellkoeffizienten
|
||||
- Predictions
|
||||
- Score (R²)
|
||||
|
||||
**Optional / zu Hause:** Untersuche den Einfluss des **Logarithmierens des Targets**
|
||||
auf die Performance der Linearen Regression.
|
||||
|
||||
## Datensatz
|
||||
|
||||
Fortsetzung des Praxisteils → **Melbourne Housing Dataset**.
|
||||
|
||||
| Datei | Inhalt |
|
||||
| ---------------------- | --------------------------------------------------- |
|
||||
| `data/melb_data_prep.csv` | aufbereiteter Datensatz (Workshop 03), Target `Price` |
|
||||
| `src/bfh_cas_pml.py` | Kursmodul mit `prep_data()` / `prep_demo_data()` |
|
||||
|
||||
Beide Dateien stammen aus den Kursmaterialien (analog `bank_data_prep.csv` + `bfh_cas_pml.py`
|
||||
bei WS6). `prep_data()` erledigt Feature-Target-Split **und** Train-Test-Split:
|
||||
|
||||
```python
|
||||
from bfh_cas_pml import prep_data
|
||||
X_train, X_test, y_train, y_test = prep_data("data/melb_data_prep.csv", "Price", seed=1234)
|
||||
```
|
||||
|
||||
**Fallback** (self-contained, falls die Kursdateien fehlen): `sklearn.datasets.fetch_california_housing`
|
||||
— ebenfalls Immobilienpreise mit rechtsschiefem Target, gut für den Log-Teil.
|
||||
|
||||
## Ordnerstruktur
|
||||
|
||||
```
|
||||
workshop8
|
||||
├── data
|
||||
│ └── melb_data_prep.csv # aus Kursmaterial (oder Fallback via sklearn)
|
||||
├── devenv.lock
|
||||
├── devenv.nix
|
||||
├── README.md
|
||||
└── src
|
||||
├── bfh_cas_pml.py # aus Kursmaterial (nur für Melbourne-Variante)
|
||||
└── linearregression.py # Lösung
|
||||
```
|
||||
|
||||
## Vorgehen
|
||||
|
||||
1. Daten laden (Variante wählen: Melbourne oder California-Fallback).
|
||||
2. **Baseline** ohne Standardisierung: `LinearRegression` fitten → `coef_`, `intercept_`, Predictions, Score festhalten.
|
||||
3. **Mit Standardisierung**: `StandardScaler` *nur auf `X_train`* fitten, dann `X_train` + `X_test` transformieren → erneut fitten, dieselben Grössen festhalten.
|
||||
4. **Vergleichen**: Koeffizienten, Predictions, Score gegenüberstellen.
|
||||
5. *(optional)* Target logarithmieren (`log1p`/`expm1`), Performance auf Originalskala vergleichen.
|
||||
|
||||
## Erkenntnisse
|
||||
|
||||
### Standardisierung (Schritte 1–3)
|
||||
|
||||
**Kernaussage:** Bei der einfachen `LinearRegression` ändert Standardisieren der Features
|
||||
**nur** Koeffizienten und Intercept (→ Interpretation), **nicht** aber Predictions und Score.
|
||||
OLS ist invariant gegenüber linearer Umskalierung der Features.
|
||||
|
||||
- **Koeffizienten** — ändern sich. Zusammenhang: `coef_std ≈ coef_roh * X_train.std(axis=0)`
|
||||
(Populations-Std, `ddof=0`). Die skalierten Koeffizienten sind „pro Standardabweichung"-Gewichte
|
||||
→ das ist das **standardisierte Regressionsgewicht β** aus dem Theorieteil. Erst dadurch werden
|
||||
die Features untereinander vergleichbar (Roh-Koeffizienten hängen an der jeweiligen Feature-Skala).
|
||||
- **Intercept** — ändert sich: von ≈ −1.06e8 (Vorhersage am unsinnigen Punkt „alle Rohwerte = 0")
|
||||
auf ≈ +1.06e6. Nach dem Skalieren liegt „alle Features = 0" beim Mittelwert jedes Features →
|
||||
dort sagt OLS gerade `y_train.mean()` voraus, also `intercept_std ≈ y_train.mean()`.
|
||||
- **Predictions** — identisch (bis auf Fliesskomma-Rauschen). OLS „sieht" eine reine Umskalierung
|
||||
der Achsen nicht: die Geometrie der Punktwolke bleibt gleich, das Modell gleicht die Skalierung
|
||||
vollständig über die Koeffizienten aus.
|
||||
- **Score (R²)** — identisch: `0.5601419746121108` vs. `…148` (Unterschied erst an der 14. Stelle
|
||||
= numerisches Rauschen aus dem unterschiedlich skalierten Gleichungssystem, kein echter Effekt).
|
||||
|
||||
**Warum bei einfacher LR egal:** OLS wird analytisch über die Normalgleichungen gelöst, kein
|
||||
iterativer Solver → die Skalierung beeinflusst weder Lösung noch Konvergenz.
|
||||
|
||||
**Wann Standardisierung _doch_ zählt:**
|
||||
|
||||
- **Ridge / Lasso**: der Strafterm ($\lambda \sum \beta_j^2$ bzw. $\lambda \sum |b_j|$) bestraft die
|
||||
Koeffizienten*grösse* — die hängt bei Rohdaten an der Feature-Skala → ungleiche Bestrafung.
|
||||
Darum „Standardisierung erforderlich" (vgl. Theorienotizen, Ridge). Hier ändert Skalieren das
|
||||
Ergebnis tatsächlich.
|
||||
- **Interpretierbarkeit / Feature-Vergleich** über β (s.o.).
|
||||
- **iterative Solver** (Gradientenverfahren): Konvergenz — bei OLS irrelevant.
|
||||
|
||||
### Log-Target (Schritt 4, optional — noch offen)
|
||||
|
||||
Anders als Feature-Scaling verändert eine **Target**-Transformation das Modell _wirklich_:
|
||||
`log(y)` modelliert einen multiplikativen statt additiven Zusammenhang.
|
||||
|
||||
Vorgehen:
|
||||
|
||||
- fit auf `np.log1p(y_train)`
|
||||
- Predictions mit `np.expm1(...)` **zurücktransformieren**, *bevor* R² auf der Originalskala gerechnet wird
|
||||
- `log1p`/`expm1` statt `log`/`exp` wegen möglicher Nullwerte (`log(0)` undefiniert)
|
||||
|
||||
Erwartung (Hypothese, selbst verifizieren):
|
||||
|
||||
- Preise sind rechtsschief → Log-Transform macht die Verteilung symmetrischer, Residuen homoskedastischer
|
||||
- `expm1` ist immer > 0 → keine negativen Preis-Vorhersagen mehr (vgl. Folien-Fazit S. 64)
|
||||
- R² auf der Originalskala kann sich ändern — **Achtung:** nicht Log-Skala mit Original-Skala vergleichen
|
||||
|
||||
## Wichtig
|
||||
|
||||
- Scaler **nur auf Trainingsdaten** fitten → sonst Data Leakage.
|
||||
- Beim Log-Target Predictions **vor** der R²-Berechnung zurücktransformieren.
|
||||
|
||||
## Quellen
|
||||
|
||||
- Foliensatz 13 (Regressionsanalyse), V. Vogel, TI BFH — Praxisteil & Folie 68
|
||||
- Notizen: `../../L5_Notizen.md`
|
||||
Reference in New Issue
Block a user