From b53476cf3bb9e9ee2fea48a58a5282be47a3fb77 Mon Sep 17 00:00:00 2001 From: aaron Date: Thu, 4 Jun 2026 13:53:41 +0200 Subject: [PATCH] feature(notizen): add notes from l4 morning --- SL/notizen/L4_Notizen.md | 293 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 293 insertions(+) create mode 100644 SL/notizen/L4_Notizen.md diff --git a/SL/notizen/L4_Notizen.md b/SL/notizen/L4_Notizen.md new file mode 100644 index 0000000..f4a404e --- /dev/null +++ b/SL/notizen/L4_Notizen.md @@ -0,0 +1,293 @@ +# Notizen SL Lektion 4 (Foliensatz 12: Algorithmen — Decision Trees) + +> Thema: Supervised Learning Algorithmen +> Datum: 04.06.2026 +> Dozentin: Violeta Vogel + +## Theorie Decision Trees + +- Ein Entscheidungsbaum ist ein Modell, das Daten anhand von Wenn-Dann-Regeln klassifiziert oder vorhersagt +- Der Baum versucht Daten so aufzuteilen, dass Gruppen möglichst **rein** werden *(rein, nicht klein — Reinheit ist das Ziel, ein reiner Knoten darf gross sein)* + - nur noch eine Klasse enthalten +- Besteht aus + - Wurzelknoten + - Entscheidungsknoten + - Blattknoten + - Äste +- Arbeitet nach Top-Down Prinzip +- Divide and Conquer + - Merkmale wählen dass die Daten am besten trennt + - Entweder mit Gini Koeffizient oder Entropie-Reduktion trennen + - Aufteilen entlang dieses Merkmales in eine oder mehrere Gruppen + - Rekursiv weiter aufteilen + - Stop wenn + - Daten in einem Knoten homogen sind + - keine sinvollen Splits mehr möglich + - maximale Tiefe erreicht +- Eigenschaften + - Gut nachvollziehbar + - Flexibel + - Geringe Anforderungen an Feature Engineering + - keine Normierung oder Skalierung + - Anfällig zu Overfitting! +- Feature Importance + - Wichtigkeit eines Features + - Wie stark trägt ein Feature zur Vorhersage bei? + - Ein Feature ist wichtig, wenn es + - oft gesplittet werden kann + - früh im Baum vorkommt + - grosse Verbesserungen der Reinheit bringt +- Zwei Arten von Feature Importance + - Impurity based Importance + - schnell + - berechnet man während des Trainings + - Importance ergibt sich aus der Summe aller Reinheitsverbesserungen, die dieses Feature bringt + - die Summen werden zum Schluss normiert, sodass alle Importances zusammen **1** ergeben *(Folie 81 — daher sind es relative Anteile)* + - Wann verwenden? + - Für erste Einschätzungen + - Um Übersicht zu gewinnen + - Wenn Modell nicht zu viele korellierte Features hat + - Permutation Importance + - robust + - langsam + - berechnet man nach dem Training + - misst wie stark die Modellleistung sinkt wenn ein Feature zufällig permutiert (durchgewürfelt) wird + - **sinkt** die Leistung stark → Feature ist wichtig → bleibt *(korrigiert: nicht „verändert sich → raus“)* + - bleibt die Leistung ~gleich → Feature unwichtig → kann raus + - permutieren über alle Features + - Wann verwenden? + - Wenn man eine verlässliche Feature-Wichtigkeit braucht + - Wenn man ein BlackBoxModel erklärbar machen will + - Prüfen auf Bias + - Importance = Baseline Score - Score nach Permutation: + 1. Zuerst Baseline Leistung messen + 2. Ein Feature permutieren + 3. Leistung erneut messen + 4. Wichtigkeitswert berechnen + +### Gini Impurity + +- misst wie wahrscheinlich es ist, dass zwei zufällig ausgewählte Elemente aus einem Knoten verschiedenen Klassen angehören +- Für einen Knoten mit Klassenanteilen p1,p2,...,pK: + - Gini = 1 - sum(i=1,k,pi^2) +- Gini = 0 -> perfekte Reinheit (nur eine Klasse) +- Gini hoch -> starke Durchmischung +- Vorteile + - Effizient + - Schneller als Entropie + - ideal für grosse Datensätze + - Gut geeignet für Random Forests +- Nachteile + - Bevorzugt Features mit vielen Splitpunkten + - Also numerische Features und solche mit vielen Kategorien + - Kann bei unbalancierten Klassen verzerren + +### Entropie + +- misst wie viel Unsicherheit in einem Datensegment steckt +- Entscheidungsbaum versucht Unsicherheit durch Splits zu reduzieren +- Für einen Knoten mit Klassenanteilen p1,p2,...,pK: + - entropie = -sum(i=1,k,pi*log2(pi)) +- Entropie = 0 -> perfekte Reinheit (nur eine Klasse) +- Entropie hoch -> starke durchmischung +- Vorteile + - hohe sensitivität + - reagiert stärker auf Veränderung als Gini + - mathematisch sauber definiert + - gute Trennung bei seltenen Klassen +- Nachteile + - höherer Rechenaufwand als Gini, da Logarithmen berechnet werden müssen + - Ähnliches Verhalten wie Gini, der Aufwand lohnt sich also nicht immer + - Kann bei stark unbalancierten Daten instabil sein + - überempfindliche Splits bei seltenen Klassen + - Kann zu tiefen Bäumen führen + - overfitting + +### Splitting + +- ist der Prozess bei dem der Entscheidungsbaum die Frage auswählt, die Daten am besten trennt +- testet viele mögliche Splits und bewertet nach Reinheitsmass +- wählt Split mit höchstem Informationsgewinn + +1. Alle features testen + - für jedes Feature mögliche Schwellenwerte prüfen + - Feature Alter -> teste 20,25,30,45 ... + - Feautre Einkommen -> teste 40k,50k,69k ... +2. für jeden Split die Reinheit berechnen + - berechnen wie "rein" die beiden entstehenden Gruppen sind, bspw. mit: + - Gini-Impurity + - Entropie + - Misclassification Error +3. Splitqualität bestimmen + - Baum misst wie stark sich die Reinheit verbessert + - je grösser Gain desto besser der Split +4. Den besten Split auswählen +5. Rekursiv weiter splitten + - bis Stopkriterium erreicht ist + +### Pruning + +- Pruning ist der Oberbegriff fürs Begrenzen der Baum-Komplexität gegen Overfitting; es gibt zwei Spielarten: Pre-Pruning (Wachstum begrenzen) und Post-Pruning (voll wachsen lassen, dann zurückschneiden) *(die Definition „nach dem Training verkleinern“ beschreibt genau genommen nur Post-Pruning)* +- Ziel ist es Overfitting zu reduzieren +- Vorteil + - reduziert overfitting + - verbessert generalisierung + - vereinfacht interpretierbarkeit + - erhöht stabilität + - verhindert unnötige splits +- Nachteile + - kann zu stark vereinfachen + - nicht immer nötig + - erfordert Validierungsdaten um optimal zu funktionieren + - rechenintensiver als pre-pruning + +### Pre-Pruning + +- setzt Wachstumsgrenzen für den Baum damit er nicht unnötig tief wird +- typische Kriterien + - maximale Tiefe + - minimale Samples pro Blatt + - minimale Verbesserung nötig für Split +- Methoden + - max_depth + - begrenzung der Baumtiefe + - min_samples_split + - nur splitten wenn genügend Datenpunkte verfügbar + - min_samples_leaf + - jedes Blatt muss mindestens n Samples enthalten + - min_impurity_decrease + - Split wird nur akzeptiert wenn er die Reinheit genügend verbessert + - max_leaf_nodes + - begrenzt die Anzahl Blätter direkt → kompakte Bäume + +### Entscheidung Pruning/Prepruning + +- Vorteile von Pre-Pruning + - schnell + - weniger Rechenaufwand + - verhindert overfitting früh + - einfachere modelle (flache bäume) sind einfacher zu verstehen +- Nachteile von Pre-Pruning + - kann gute Spliuts verhindern wenn Grenzen zu streng sind + - erfordert Hyperparameter-Tuning -> sonst Underfitting + - weniger flexibel als Post-Pruning + + ### Post-Pruning + +- Post-Pruning schneided bereits gewachsene Bäume zurück um Overfitting zu reduzieren +- Methoden + - Cost-Complexity-Pruning *(in sklearn: Parameter `ccp_alpha`)* + - Reduced Error Pruning +- Vorteile + - robuster gegenüber neuen Daten + - verbessert generalisierung + - flexibler als Pre-Pruning, der Baum darf zuerst alle Muster entdecken +- Nachteile + - rechenintensiver + - benötigt Validierungsdaten + - komplexere Implementierung + +## Decision Tree Classifier + +- ist ein überwachter Machine-Learning-Algorihmus der Daten anhand einer Reihe von regelbasierten Entscheidungen klassifiziert +- Erstell ein umgedrehtes Baumdiegramm + - oben ist das wichtigste Merkmal + - jede Antwort führt zu einem neuen Ast und zu einer weiteren Frage + - bis ein Blattknoten erreicht wird, der die finale Klassenzuordnung enthält + +--- + +## Praxis: Decision Tree Classifier (Code) + +> Ergänzung zu den übersprungenen Praxis-Folien (bis Workshop 5). Datengrundlage: +> vorbereiteter Bank-Datensatz, geladen über das Kursmodul `bfh_cas_pml`. + +### Basismodell + +```python +from bfh_cas_pml import prep_data +from sklearn.tree import DecisionTreeClassifier + +X_train, X_test, y_train, y_test = prep_data('bank_data_prep.csv', 'y', seed=1234) + +model = DecisionTreeClassifier(random_state=1234) # random_state nur für Reproduzierbarkeit +model.fit(X_train, y_train) +print(model.score(X_test, y_test)) # ≈ 0.83 +``` + +### Diagnose — Overfitting sichtbar machen + +```python +print('depth :', model.get_depth()) # 28 +print('leaves:', model.get_n_leaves()) # 777 +print('train :', model.score(X_train, y_train)) # 1.0 <- perfekt +print('test :', model.score(X_test, y_test)) # 0.83 +``` + +`train=1.0` vs `test=0.83` ist das Lehrbuch-Symptom: der voll ausgewachsene Baum +memoriert die Trainingsdaten (jedes Blatt rein), generalisiert aber schlecht. +→ Abhilfe = Pruning. + +### Pre-Pruning per Hyperparameter-Tuning (Workshop 5: `min_impurity_decrease`) + +Ein Split wird nur gemacht, wenn er die Impurity um mindestens diesen Wert senkt — +**normiert auf den ganzen Baum und gewichtet nach Knotengröße**: + +``` +ΔI_norm = (N_node / N_total) * ( I_parent - w_left*I_left - w_right*I_right ) +``` + +Folge: tiefe Knoten betreffen wenige Samples → ihr ΔI_norm ist winzig → sinnvolle +Schwellen liegen bei ~1e-4 … 1e-2 (Float → `np.arange`, nicht `range`). + +```python +import numpy as np + +model = DecisionTreeClassifier(random_state=1234) +params = np.arange(0, 0.004, 0.0002) +scores = [] +for p in params: + model.set_params(min_impurity_decrease=p) + model.fit(X_train, y_train) + scores.append(model.score(X_test, y_test)) + +best_i = np.argmax(scores) # Index des Maximums +print(f'best={scores[best_i]:.4f} @ {params[best_i]}') # ~0.879 @ 0.0004 +``` + +Vorgehen = Wertebereich **schrittweise eingrenzen** (grob → fein). Erwarteter +Kurvenverlauf: kurzer Anstieg/Bump über der Baseline (0.83), dann Abfall, sobald +nützliche Splits wegfallen; im Extrem Stumpf → Accuracy ≈ Mehrheitsklasse. + +> ⚠ Methodik-Caveat: hier wird gegen `X_test` getunt → **optimistic bias** (wie +> in W4). Der „beste“ Score ist optimistisch verzerrt; sauber wäre ein +> Validation-Split bzw. CV. + +### Baum visualisieren (gepruntes Modell) + +```python +from bfh_cas_pml import inspect_decision_tree_model +inspect_decision_tree_model( + DecisionTreeClassifier(min_impurity_decrease=0.0004, random_state=1234), + X_train, y_train) +# druckt depth/leaves/score und zeichnet plot_tree -> der geprunte Baum ist klein & lesbar +``` + +### Feature Importance (impurity-based) + +```python +import pandas as pd +import seaborn as sns + +imp = pd.Series(model.feature_importances_, index=X_train.columns).sort_values() +sns.barplot(x=imp.values, y=imp.index) # horizontaler Bar-Chart wie auf Folie 83 +# Top-Features im Bank-Set: duration, nr_employed, month, euribor3m, age +``` + +Permutation Importance (robuster, in den Folien nur als Theorie): + +```python +from sklearn.inspection import permutation_importance +r = permutation_importance(model, X_test, y_test, n_repeats=10, random_state=1234) +perm = pd.Series(r.importances_mean, index=X_train.columns).sort_values() +```