Files
cas-pml/SL/notizen/L3_Notizen.md
T

7.4 KiB
Raw Blame History

Notizen SL Lektion 3

Thema: Feature Engineering Datum: 28.05.2026 Dozentin: Violeta Vogel

Recap

  • Sandbox Prinzip
    • Daten werden immer als Kopie bearbeitet (data = ori_data.copy()), damit Transformationsschritte sich nicht gegenseitig beeinflussen und die Ausgangsdaten nicht neu geladen werden müssen
  • hohe Kardinalität
    • bezeichnet eine hohe Anzahl an eindeutigen Werten

Arten von Variablen

  • Numerische Variablen
    • messbare Zahlen
    • Stetig (kontinuierlich)
      • Können jeden beliebigen Wert annehmen und unendlich fein unterteilt werden.
      • Beispiele: Körpergröße, Gewicht, Temperatur, Zeit
    • Diskret
      • Können nur in bestimmten, meist ganzzahligen Schritten gezählt werden.
      • Beispiele: Anzahl der Kinder, Autoverkäufe, Besucher eines Konzerts
  • Kategoriale Variablen
    • Gruppen oder Eigenschaften
    • Diese Variablen teilen Beobachtungen in verschiedene Gruppen oder Kategorien ein. Sie geben eine Eigenschaft an.
    • Nominal
      • Die Kategorien haben keine logische Reihenfolge.
      • Beispiele: Geschlecht, Haarfarbe, Augenfarbe, Postleitzahlen.
    • Ordinal
      • Die Kategorien haben eine natürliche Rangordnung oder Reihenfolge.
      • Beispiele: Zufriedenheitsgrade (sehr zufrieden, zufrieden, unzufrieden), Schulnoten (1 bis 6)

Transformationen: Numerisieren Kategorialer Variablen

  • Numerisieren
    • Numerische Darstellung einer Variablen, damit ML damit rechnen kann
    • Verschiedene Methoden
      • Faktorisieren
      • Ordinal Encodieren
      • Nominal Encodieren
    • Faustregel: nominal → One-Hot, ordinal → Ordinal Encoding, reines Label ohne Bedeutung → Faktorisieren

Faktorisieren

  • Jeder Kategorie einer kategorialen Variablen wird ein Integer-Wert zugeordnet, beginnend bei 0
  • data.job = pd.factorize(data.job)[0]
    • pd.factorize() gibt ein Tupel zurück:
      • [0] → faktorisierte Werte (numpy.ndarray), beginnend bei 0
      • [1] → Index mit der Zuordnung der Werte zu den Ausgangswerten
  • Werte werden per Default in Reihenfolge des Auftretens im Dataset vergeben (nicht sortiert)
  • mit sort=True werden sie lexikografisch (bezogen auf die Ausgangswerte) vergeben
  • Schwäche: die numerische Zuordnung ist im Grunde willkürlich (Reihenfolge im Datensatz) → es wird eine Ordnung impliziert, die inhaltlich keine ist. Taugt sauber nur für nominale Daten, wo die Zahl reines Label ist.

Ordinal Encodieren

  • Behebt die Faktorisier-Schwäche: bei einer tatsächlich ordinalen Variable werden die Zahlen gezielt der natürlichen Rangordnung zugeordnet
  • Beispiel education:
    • illiterate → 0
    • unknown → 0
    • basic.4y → 1
    • basic.6y → 2
    • basic.9y → 3
    • professional.course → 4
    • high.school → 5
    • university.degree → 6
  • Umsetzung über .replace() mit einem (verschachtelten) Dictionary, das vorher definiert wird:
    data.replace(replace_nums, inplace=True)
    
  • Hinweis: sklearn.preprocessing.OrdinalEncoder macht in Wahrheit nur eine Faktorisierung — echtes ordinales Mapping erfordert deutlich aufwändigere Parametrisierung.

Spezialfall: 0-1 Encodieren

  • Bei nur zwei Kategorien reicht np.where:
    data['contact'] = np.where(data.contact == 'cellular', 1, 0)
    
  • Achtung: alles, was nicht cellular ist, wird 0 (inkl. NAs)
  • Danach ggf. Spalte umbenennen für Transparenz:
    data.rename(columns={'contact': 'contact_cellular'}, inplace=True)
    

Nominal Encodieren (One-Hot)

  • Für Variablen ohne Rangordnung — hier wäre eine ordinale Zahl irreführend
  • pd.get_dummies() erstellt pro Kategorie eine neue Dummy-Variable (0/1) und entfernt die Ausgangsvariable
  • Wichtige Parameter:
    • drop_first=True → eine Dummy weniger als Kategorien (vermeidet perfekte Multikollinearität / Dummy-Trap)
    • prefix='marital' → benennt die neuen Spalten mit Präfix (sinnvoll bei mehreren Variablen)
    • columns=[...] → mehrere Variablen auf einmal
  • Trick für alle kategorialen Spalten außer Target:
    target = 'y'
    sel_vars = data.select_dtypes(include=['object']).columns.drop(target)
    data = pd.get_dummies(data, columns=sel_vars, drop_first=True)
    

Transformationen: Numerische Variablen

Hinweis: Normalisieren und Standardisieren sind Unterarten von Skalieren, nicht drei gleichrangige Methoden.

  • Methoden
    • Skalieren
      • Normalisieren
      • Standardisieren
    • Binning

Skalieren

  • Bringt numerische Variablen auf vergleichbare Wertebereiche
  • Nur sinnvoll, wenn auf alle relevanten Variablen gleich angewendet
  • Muss ggf. für spätere neue Daten gespeichert werden → daher in der Praxis sklearn.preprocessing statt Handformel:
    • MinMaxScaler → Normalisierung
    • StandardScaler → Standardisierung
  • .set_output(transform="pandas") behält den DataFrame, statt ein numpy-Array zurückzugeben:
    from sklearn.preprocessing import MinMaxScaler
    scaler = MinMaxScaler().set_output(transform="pandas")
    data = scaler.fit_transform(data)
    

Normalisieren

  • Skaliert auf festen Bereich [0, 1]
  • Formel: (x - min) / (max - min)
  • min → 0, max → 1

Standardisieren

  • Zentriert auf Mittelwert 0, Standardabweichung 1 (z-Transformation)
  • Formel: (x - mean) / std
  • danach: mean ≈ 0, std = 1

Wichtig: Keines der beiden Verfahren ändert die Form der Verteilung — nur die Skala der x-Achse. Schiefe bleibt schief.

Binning

  • Numerische Variable in Klassen/Bins zusammenfassen → wird quasi (ordinal-)kategorial
  • Equal Binning: teilt minmax in gleich breite Bereiche
    bins = 10
    data.age = pd.cut(data.age, bins=bins, labels=list(range(1, bins + 1)))
    
  • Custom Bins: eigene Grenzen, nützlich bei stark schiefen Verteilungen
    data.campaign = pd.cut(
        data.campaign,
        bins=[0, 1, 2, 3, 4, 5, 10, 1000],
        labels=[1, 2, 3, 4, 5, '6-10', '>10'])
    
  • Zur optimalen Bin-Anzahl gibt es keinen Konsens (Freedman-Diaconis, Sturges, …) → experimentell ermitteln

Konstruktion

  • Neue Variablen aus bestehenden ableiten
  • Ziele: Komplexität reduzieren, Korrelationen vermeiden
  • Beispiel zyklische Daten (Windrichtung): 359° und 1° sind nah beieinander, numerisch aber weit weg → Zerlegung in sin/cos-Komponenten löst das
    data['x'] = np.sin(data.direction * np.pi / 180) * data.speed
    data['y'] = np.cos(data.direction * np.pi / 180) * data.speed
    
    • allgemein relevant für alles Zyklische (Stunden, Monate, Winkel)
  • Beispiel Datum: String → pd.to_datetime(), dann Komponenten extrahieren
    data['date_dt'] = pd.to_datetime(data.Date, format="%d/%m/%Y")
    data['year']  = data.date_dt.dt.year
    data['month'] = data.date_dt.dt.month
    data['day']   = data.date_dt.dt.day
    
    • oder Differenzen zu einem Startdatum ((data.date_dt - start_date).dt.days)

Bereinigen von Variablennamen

  • Nach One-Hot entstehen Namen mit Leerzeichen / Bindestrichen / Punkten (job_blue collar, emp.var.rate), die manche ML-Frameworks als Bezeichner ablehnen
  • Erlaubte Zeichen: a-z, A-Z, 0-9, _
  • Per Regex unerlaubte Zeichen durch _ ersetzen:
    new_names = old_names.str.replace('[^a-zA-Z0-9_]', '_', regex=True)