feature: update readme, add more output to ml-pipeline

This commit is contained in:
2026-05-28 14:39:00 +02:00
parent e397f031cc
commit 1410c6c990
2 changed files with 60 additions and 8 deletions
+58 -8
View File
@@ -8,7 +8,7 @@ den in Workshop 2 erarbeiteten und konsolidierten Empfehlungen.
- **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
einzige Quelle der Wahrheit für die anzuwendenden Transformationen das
ursprüngliche `WS_03_Empfehlungen.xlsx` muss nicht geöffnet werden.
## Aufgabenstellung
@@ -16,7 +16,7 @@ ursprüngliche `WS_03_Empfehlungen.xlsx` muss nicht geöffnet werden.
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.
keine neue Exploration statt die Entscheidungen sind bereits getroffen.
## Drehbuch (Transformationsliste)
@@ -89,10 +89,60 @@ workshop3
python src/prepare.py
```
## Offene Punkte / Selbstcheck
## Selbstcheck (geklärt)
- [ ] `YearBuilt == 1196` verifizieren (vermutlich Tippfehler für 1996)
- [ ] NA-Spalten prüfen -> sind NAs in der Target-Variable `Price`?
(Falls ja: Zeilen entfernen statt Median einsetzen.)
- [ ] Standardisieren bleibt hier aus -> relevant erst beim Training,
und modellabhängig (Bäume brauchen es nicht).
- [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.
+2
View File
@@ -27,6 +27,7 @@ def inspect(df: pd.DataFrame) -> None:
def e1_remove_observations(df: pd.DataFrame) -> pd.DataFrame:
"""E1: Ausreisser und fehlerhafte Beobachtungen entfernen."""
df.info()
before = len(df)
df = df[df.Price < 8000000] # nur Werte bis 8000000 berücksichtigen
df = df[
@@ -134,6 +135,7 @@ def e41_construct(df: pd.DataFrame) -> pd.DataFrame:
def e42_clean_names(df: pd.DataFrame) -> pd.DataFrame:
"""E4.2: Unerlaubte Zeichen in Spaltennamen durch _ ersetzen."""
df.columns = df.columns.str.replace(r"[^a-zA-Z0-9_]", "_", regex=True)
df.info()
return df
if __name__ == "__main__":