Files
cas-pml/SL/aufgaben/workshop3/README.md
T

149 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Workshop 3 Feature Engineering: Melbourne Housing Dataset
Aufbereitung des **Melbourne Housing Datasets** für Supervised Learning, gemäss
den in Workshop 2 erarbeiteten und konsolidierten Empfehlungen.
- **Input:** `data/melb_data.csv` (Rohdaten)
- **Output:** `data/melb_data_prep.csv` (aufbereitet)
- **Pipeline:** `src/prepare.py`
Die Empfehlungen stammen aus der EDA in Workshop 2. Dieses README ist die
einzige Quelle der Wahrheit für die anzuwendenden Transformationen — das
ursprüngliche `WS_03_Empfehlungen.xlsx` muss nicht geöffnet werden.
## Aufgabenstellung
Das Dataset wurde in Workshop 2 mit Sicht auf Machine Learning untersucht.
Die daraus abgeleiteten Empfehlungen (siehe unten) werden hier in einer
deterministischen Pipeline `CSV rein → CSV raus` implementiert. Es findet
keine neue Exploration statt — die Entscheidungen sind bereits getroffen.
## Drehbuch (Transformationsliste)
### 1. Data Frame
| # | Transformation | Details |
|-----|----------------|---------|
| 1.1 | Beobachtungen nach Bedingung entfernen | `Price >= 8000000`; `YearBuilt == 1196` |
| 1.2 | Duplikate entfernen | kein Bedarf |
| 1.3 | Fragwürdige Variablen entfernen | `Unnamed: 0`, `Suburb`, `Address`, `SellerG`, `Postcode`, `Bedroom2` |
| 1.4 | NAs ersetzen | kategoriale: Modalwert · numerische: Median |
### 2. Kategoriale Variablen
| # | Transformation | Details |
|-----|----------------|---------|
| 2.1 | Kardinalität reduzieren | `Regionname`: `* Victoria``Victoria` · `Method`: `SA``S` |
| 2.2 | Faktorisieren | `CouncilArea` |
| 2.3 | Ordinal encodieren | `Type`: `h, u, t``1, 2, 3` |
| 2.4 | Binär encodieren | kein Bedarf |
| 2.5 | Nominal encodieren (One-Hot) | alle verbleibenden kategorialen Variablen ausser `Date` |
### 3. Numerische Variablen
| # | Transformation | Details |
|-----|----------------|---------|
| 3.1 | Logarithmieren (+ umbenennen) | `Landsize``logLandsize` · `BuildingArea``logBuildingArea` |
| 3.2 | Binär umcodieren | kein Bedarf |
### 4. Andere Tätigkeiten
| # | Transformation | Details |
|-----|----------------|---------|
| 4.1 | Konstruktion | `Date``month`, `year`, `day_of_week`; danach `Date` droppen |
| 4.2 | Variablennamen bereinigen | unerwünschte Zeichen → `_` |
| 4.3 | Standardisieren | kein Bedarf |
| 4.4 | Speichern | als `melb_data_prep.csv` |
## Reihenfolge — wichtig
Die Schritte sind nicht beliebig vertauschbar. Insbesondere:
- **1.1 vor 1.4:** erst Ausreisser/fehlerhafte Zeilen raus, dann NAs füllen
(sonst fliessen Schrottwerte in Median/Modalwert ein).
- **2.1 vor 2.5:** erst Kardinalität reduzieren, dann One-Hot
(sonst entstehen Dummy-Spalten für Levels, die man gerade zusammenlegen will).
- **2.5 nach allen anderen kategorialen Schritten:** One-Hot greift alle
*übrigen* `object`-Spalten ab — `CouncilArea` und `Type` sind dann schon
numerisch und werden korrekt übersprungen.
- **4.1 vor 2.5 ODER `Date` explizit ausnehmen:** `Date` ist `object` und würde
sonst von One-Hot zerlegt. Lösung: `Date` beim One-Hot ignorieren und erst in
4.1 zu `month`/`year`/`day_of_week` zerlegen.
## Projektstruktur
```
workshop3
├── data/
│ ├── melb_data.csv # Rohdaten (Input)
│ └── melb_data_prep.csv # aufbereitet (Output, generiert)
├── src/
│ └── prepare.py # Pipeline
├── devenv.nix
└── README.md
```
## Ausführen
```sh
python src/prepare.py
```
## Selbstcheck (geklärt)
- [x] `YearBuilt == 1196` verifiziert: nächster Wert ist 1830, Sprung von 634
Jahren, physikalisch unmöglich (Melbourne ~1835 gegründet) → Datenfehler,
eine Zeile entfernt.
- [x] NAs in Target `Price`? Nein — Spalte ist vollständig (18396 non-null).
Median-Imputation in E4 daher unkritisch.
- [x] Standardisieren bleibt aus — modellabhängig, gehört ans Training, nicht in
die Aufbereitung (Bäume brauchen es nie).
## Ergebnis
- 18'393 Zeilen (von 18'396, 3 in 1.1), 24 Spalten
- keine `object`-Spalten mehr -> alles numerisch (`int`, `float`, `bool`)
- Output: `data/melb_data_prep.csv`
Spaltenrechnung zur Kontrolle: 16 nach NA-Imputation → +8/2 durch One-Hot (22)
1 `Date`/+3 Datumskomponenten (24).
## Implementierungs-Notizen (Abweichungen von den Vorlagen)
Bewusste Entscheidungen, die von `1.6 Implementation.ipynb` (Bank) bzw. der
WS-03-Musterlösung abweichen:
- **Reine `df -> df`-Funktionen statt `inplace=True`.** Jede Transformation
gibt einen neuen DataFrame zurück. Vermeidet `SettingWithCopyWarning` auf
Slices und ist Copy-on-Write-sicher (pandas 3.x). Pipeline-Struktur:
`df = e1(df); df = e2(df); …`.
- **`.map({...})` statt `.replace([...], [...])`** beim Ordinal-Encoding von
`Type`. Vermeidet die Downcasting-`FutureWarning` und ist lesbarer
(Kategorie→Zahl direkt nebeneinander statt positionsabhängige Listen).
- **`.fillna()` statt `SimpleImputer`** für die NA-Imputation. KISS — kein
sklearn-Objekt nötig, da hier keine spätere Inference auf neuen Daten
stattfindet (kein Bedarf, die Imputationswerte zu persistieren).
- **Vektor-Operation `df.columns.str.replace(...)` statt `for`-Loop** beim
Bereinigen der Variablennamen.
- **`+ 1` statt `+ min + 1`** beim Logarithmieren. Flächen sind nie negativ
(Minimum 0), daher reicht `+1`, um `log10(0)` zu vermeiden. `Landsize` hat
1942 Nullwerte (~10,5 %) — ohne `+1` wären das ebenso viele `-inf`.
## Offene Punkte für ein echtes Projekt (hier bewusst nicht gemacht)
Über das Drehbuch hinausgehende Überlegungen, fürs nächste Dataset:
- **Zyklische Datums-Features.** `month` und `day_of_week` sind linear codiert
(Dez→Jan sieht als 12→1 wie ein grosser Sprung aus). Sauberer wäre eine
sin/cos-Zerlegung. Für baum-basierte Modelle irrelevant, für lineare relevant.
- **NA-Anteil bei `BuildingArea` (58 %) und `YearBuilt` (51 %).** Median-Füllung
über die halbe Spalte drückt deren Varianz stark. Kandidat für „Variable
droppen" oder modellbasiertes Imputieren statt pauschalem Median.
- **`CouncilArea`-Faktorisierung erzeugt Schein-Ordnung.** 33 nominale Levels
als 0..32 codiert — ein lineares Modell liest daraus eine Rangordnung, die
nicht existiert. Bewusster Trade-off gegen 33 One-Hot-Spalten. Für Bäume
unproblematisch.
- **Produktionsform.** Für eine wiederverwendbare Pipeline (auch auf neuen
Daten) wäre `sklearn` `Pipeline` + `ColumnTransformer` die nächste Stufe —
löst zugleich das Persistenz-Problem der Imputations-/Skalierungswerte.