Files

Workshop 05 — Decision Tree Classifier: min_impurity_decrease Tuning

Aufgabe

Untersuchen, wie verschiedene Werte von min_impurity_decrease beim DecisionTreeClassifier die erreichbare Test-Accuracy beeinflussen.

  • Wertebereich schrittweise eingrenzen (grob → fein).
  • Resultate darstellen:
    • grafisch als Liniendiagramm (Parameter vs. Accuracy),
    • in der Konsole: bester Score + zugehöriger Parameterwert.

Hinweis aus den Folien: range() liefert Ganzzahlen, np.arange() liefert Gleitkommawerte. min_impurity_decrease ist ein Float → np.arange.

Setup

devenv shell        # python + venv (pandas, numpy, sklearn, matplotlib, seaborn)

Datengrundlage = vorbereiteter Bank-Datensatz aus W4. Geladen über das kursinterne Modul (muss auf dem PYTHONPATH / im Projektordner liegen):

from bfh_cas_pml import prep_data
X_train, X_test, y_train, y_test = prep_data('bank_data_prep.csv', 'y', seed=1234)

Baseline zum Abgleich (voll ausgewachsener Baum):

DecisionTreeClassifier(random_state=1234)  # train=1.0, test≈0.8296 → overfit

Falls bfh_cas_pml / bank_data_prep.csv nicht zur Hand sind: als Fallback tut es jeder train_test_split auf einem sklearn-Datensatz — die Mechanik des Sweeps bleibt identisch.

Theorie — was min_impurity_decrease tut

Ein Split wird nur ausgeführt, wenn er die (gewichtete, auf den ganzen Baum normierte) Impurity um mindestens diesen Wert senkt:

ΔI_norm = (N_node / N_total) * ( I_parent
                                 - (N_left/N_node)  * I_left
                                 - (N_right/N_node) * I_right )

Kernpunkte fürs Verständnis:

  • Es ist eine Pre-Pruning-Schwelle: schwache Splits werden gar nicht erst gemacht → der Baum bleibt kleiner → weniger Overfitting.
  • Der Wert ist mit dem Anteil der Beobachtungen im Knoten gewichtet (N_node / N_total). Tiefe Knoten betreffen wenige Samples → ihr ΔI_norm ist winzig. Darum liegen sinnvolle Schwellen im Bereich ~1e-4 bis ~1e-2, nicht bei 0.1+. (Vgl. das Folien-Rechenbeispiel: ein guter Split nahe der Wurzel ergab 0.0421.)
  • =0 → kein Pruning → Baseline-Baum (overfit).

Vorgehen — Eingrenzung (der eigentliche Lerninhalt)

  1. Grob: weiter Bereich, grobe Schritte, um die Region des Maximums zu lokalisieren — z. B. np.arange(0, 0.02, 0.001).
  2. Fein: um das gefundene Maximum herum zoomen — z. B. np.arange(0, 0.004, 0.0002).
  3. Wiederholen, bis Lage/Wert des Peaks stabil sind.

Jede Iteration ist ein eigener Sweep (gleicher Loop, anderer np.arange). Im README/Notes die drei (o. ä.) Ranges + jeweils Peak dokumentieren — das ist die geforderte „schrittweise Eingrenzung“.

Erwartetes Verhalten (Sanity-Check)

  • Bei 0 startest du auf der Baseline (~0.83).
  • Mit steigendem Wert zunächst Plateau / leichter Bump (Rausch-Splits werden entfernt), dann Kante nach unten, sobald nützliche Splits wegfallen.
  • Im Extrem degeneriert der Baum zum Stumpf → Accuracy = Mehrheitsklasse. Der Bank-Datensatz wurde in W4 ~balanciert resampled → Floor liegt nahe ~0.5. Wenn deine Kurve dort hin abstürzt, ist das korrekt, kein Bug.

Deliverables

  • Loop über np.arange-Range, set_params(min_impurity_decrease=p), fit, score(X_test, y_test), sammeln.
  • sns.lineplot(x=params, y=scores) + Scatter-Marker auf max(scores), Achsen beschriftet (min_impurity_decrease / accuracy).
  • Konsole: best score + zugehöriger Parameterwert.
  • Mind. 2 Eingrenzungs-Stufen (grob + fein) dokumentiert.

Caveats / Vertiefung (optional)

  • Optimistic bias (wie in W4): hier wird min_impurity_decrease direkt gegen X_test getunt — derselbe Trap wie die manuelle Grid-Search ohne CV. Der gemeldete „beste“ Score ist dadurch optimistisch verzerrt. Die Folien machen es so; fürs Deliverable also bewusst übernehmen, aber als Deviation notieren. Sauber wäre Tuning auf einem Validation-Split bzw. GridSearchCV.
  • Verwandter Faden, falls Zeit/Interesse: ccp_alpha (Cost-Complexity / Minimal-Cost-Complexity-Pruning) ist sklearns „eigentlicher“ Pruning-Knopf und liefert via cost_complexity_pruning_path() direkt eine sinnvolle Kandidatenliste statt manueller np.arange-Rate-Erei — nur als Zeiger, nicht Teil der Aufgabe.