Worum geht’s
Die beiden vorangegangenen Themen haben das maschinelle Lernen als Idee entwickelt: ein Modell aus Daten schätzen (3.1), Klassen trennen (3.2). Dieses Kapitel beantwortet die unromantische Anschlussfrage — womit rechnet man das eigentlich? Die Antwort der Praxis ist erstaunlich einheitlich: ein Stapel aus wenigen Python-Bibliotheken, der seit gut einem Jahrzehnt den De-facto-Standard bildet. NumPy liefert das schnelle n-dimensionale Array, pandas die tabellarische Sicht mit benannten Spalten, scikit-learn die Algorithmen hinter einer bemerkenswert konsequenten Schnittstelle — und Matplotlib mit Seaborn die Visualisierung. Genau diese vier nennt auch der Foliensatz als die Werkzeuge der Wahl, jeweils mit Verweis auf ein Cheat-Sheet bzw. die offizielle Dokumentation.
Mich reizt an diesem Thema weniger eine neue Theorie als eine Abstraktion:
scikit-learn presst kNN, Entscheidungsbaum, SVM und logistische Regression — vier
mathematisch grundverschiedene Verfahren — in genau drei Methoden, fit,
predict, score. Diese Einheitlichkeit ist kein kosmetisches Detail, sondern
das, was den fairen Vergleich von Modellen überhaupt erst billig macht: Man
tauscht eine Zeile aus, der Rest der Auswertung bleibt stehen. Genau das mache ich
unten — ein und derselbe Datensatz, vier Modelle, eine Schleife. Damit wird die
„Mechanik” hinter 3.1 und 3.2 zu lauffähigem Code, und nebenbei trägt dieser
Stack das gesamte Praxis-Gerüst dieses Portfolios: jede <Figure>, die ich
zeige, entsteht in derselben uv2nix-Umgebung.
Kernkonzepte
Der Stack in Schichten
Die Bibliotheken bauen aufeinander auf, jede mit einer klaren Aufgabe — von der rohen Array-Ebene bis zur fertigen Abbildung.
Die Estimator-API: fit / predict / score
Das tragende Designprinzip von scikit-learn ist, dass jedes lernende Objekt ein
Estimator ist und dieselben Methoden anbietet. Ein Modell lernt mit
est.fit(X, y), sagt mit est.predict(X_neu) vorher, und bewertet sich selbst
mit est.score(X, y). Vorverarbeitungsschritte (Skalierer, Encoder) sind
Transformer und ergänzen transform(X). Diese Uniformität ist der Grund,
warum man Modelle wie Bauteile austauschen kann.
Pipelines: Vorverarbeitung und Modell als eine Einheit
Wer den Scaler separat auf den gesamten Datensatz fittet und danach
kreuzvalidiert, begeht ein subtiles Datenleck: Der Mittelwert hat dann
schon Information aus dem Validierungsfaltblatt gesehen. Die Pipeline
verhindert das, indem sie Transformer und Estimator zu einem Estimator
verklebt — fit fittet erst den Scaler, dann das Modell, und zwar bei jeder
Kreuzvalidierungs-Falte neu auf deren Trainingsanteil.
Kategoriale Merkmale: Encoding
Reale Tabellen enthalten Text-Spalten („Stadt”, „Produktklasse”). Modelle
rechnen aber mit Zahlen. One-Hot-Encoding ersetzt eine kategoriale Spalte mit
Ausprägungen durch binäre Indikatorspalten — so wird keine künstliche
Ordnung suggeriert, wie es ein naives Durchnummerieren täte. Im Stack erledigt das
OneHotEncoder, meist eingebettet in einen ColumnTransformer, der numerische und
kategoriale Spalten parallel behandelt.
Saubere Bewertung: train_test_split und cross_val_score
Ein Modell an denselben Daten zu messen, an denen es gelernt hat, belohnt
Auswendiglernen. train_test_split trennt deshalb einen Hold-out-Teil ab.
Robuster noch ist die k-fache Kreuzvalidierung: Die Daten werden in
Blöcke geteilt, -mal auf Blöcken trainiert und auf dem ausgelassenen
getestet. cross_val_score liefert die Genauigkeiten; ihr Mittel schätzt die
Generalisierung, ihre Streuung deren Verlässlichkeit. Die stratifizierte
Variante hält dabei die Klassenanteile in jeder Falte konstant.
Praxis
Es gibt zu diesem Foliensatz kein Übungsblatt. Stattdessen baue ich das kanonische scikit-learn-Beispiel nach — den Klassifikator-Vergleich — und nutze ihn, um die obigen Begriffe an einem konkreten Datensatz sichtbar zu machen. Vier Modelle, jedes in derselben Pipeline, bewertet per Kreuzvalidierung, und ihre Entscheidungsgrenzen nebeneinander gezeichnet.
Der Kern ist die Uniformität der API: Vier grundverschiedene Verfahren stehen in
einem Dictionary, jedes in identischer StandardScaler-Pipeline.
def _make_models() -> dict[str, Pipeline]:
return {
"k-NN (k=5)": Pipeline([("scale", StandardScaler()),
("clf", KNeighborsClassifier(n_neighbors=5))]),
"Entscheidungsbaum": Pipeline([("scale", StandardScaler()),
("clf", DecisionTreeClassifier(max_depth=4))]),
"SVM (RBF)": Pipeline([("scale", StandardScaler()),
("clf", SVC(kernel="rbf", C=1.0))]),
"Logistische Regression": Pipeline([("scale", StandardScaler()),
("clf", LogisticRegression())]),
}
cv = StratifiedKFold(n_splits=5, shuffle=True, random_state=SEED)
for name, model in _make_models().items():
s = cross_val_score(model, X, y, cv=cv, scoring="accuracy") # eine Zeile pro Modell
print(f"{name}: {s.mean()*100:.1f} % ± {s.std()*100:.1f}")
Der Datensatz ist absichtlich nicht linear trennbar (make_classification mit
zwei Clustern je Klasse) — sonst sähen alle vier Grenzen gleich aus und der
Vergleich verschenkte seine Pointe. Das vollständige Skript liegt in
python/src/eport_figures/praxis/p_3_3_ml_python.py. Seine Ausgabe:
Datensatz: make_classification, X.shape = (300, 2), Klassen = [152, 148]
X-Typ: ndarray dtype=float64 y-Typ: ndarray
Kreuzvalidierung (5-fach, stratifiziert) — CV-Genauigkeit:
k-NN (k=5) 88.3 % ± 3.0 Falten: [0.867, 0.933, 0.85, 0.9, 0.867]
Entscheidungsbaum 88.7 % ± 4.4 Falten: [0.85, 0.967, 0.867, 0.9, 0.85]
SVM (RBF) 89.3 % ± 3.9 Falten: [0.867, 0.933, 0.833, 0.933, 0.9]
Logistische Regression 87.0 % ± 4.1 Falten: [0.883, 0.933, 0.833, 0.883, 0.817]
Bestes Modell auf diesem Datensatz: SVM (RBF) (89.3 %).
Hold-out-Genauigkeit (ein 75/25-Split, train_test_split):
k-NN (k=5) 88.0 %
Entscheidungsbaum 92.0 %
SVM (RBF) 88.0 %
Logistische Regression 86.7 %
Vier Klassifikatoren, ein Datensatz. Man sieht den induktiven Bias jedes Verfahrens unmittelbar: die logistische Regression zieht eine einzige Gerade (linear), der Entscheidungsbaum schneidet rein achsenparallel (treppenförmig), kNN folgt lokal jeder Punktwolke (zerklüftet), die RBF-SVM legt eine glatte, geschwungene Grenze.
Mittlere CV-Genauigkeit mit Standardabweichung über die fünf Falten. Die Modelle liegen in einem Band von etwa 87–89 % — und die Fehlerbalken überlappen deutlich.
Die eigentliche Lehre steckt nicht im Sieger, sondern in dessen Knappheit: Auf diesem Datensatz trennen 2,3 Prozentpunkte das beste vom schlechtesten Modell, bei Standardabweichungen von 3–4 Punkten. Die Fehlerbalken überlappen vollständig — der Unterschied ist statistisch nicht belastbar. Genau deshalb darf man ein Modell nie an einer einzelnen Zahl festmachen; der Hold-out-Split bestätigt das, indem er eine andere Reihenfolge produziert (dort führt der Baum mit 92 %). Die Kreuzvalidierung über mehrere Falten ist die ehrlichere Schätzung, weil sie die Streuung mitliefert — eine Brücke direkt zu Thema 3.4.
Querbezüge
- 3.1 / 3.2 (ML-Grundlagen, Klassifikation): Dieses Kapitel ist deren Implementierung. Die logistische Regression in der Pipeline ist der lineare Klassifikator aus 3.2; die RBF-SVM zeigt, was der Kern-Trick aus 3.2 in der Praxis bedeutet — eine glatte nichtlineare Grenze, ohne den Merkmalsraum je explizit aufzuspannen. Der Entscheidungsbaum verbindet zurück zu den Baumverfahren aus 3.1.
- 3.4 (Evaluierung): Die Kreuzvalidierung hier ist nur die Spitze. Dass die vier Modelle innerhalb ihrer Fehlerbalken ununterscheidbar sind, ist genau das Thema von 3.4 — Genauigkeit ist nur eine Metrik, und ein einzelner Wert ohne Streuung führt in die Irre.
- 7.1 (Neuronale Netze): Dasselbe Stack-Argument. Das dortige Perzeptron ist
in reinem NumPy gebaut; ein
MLPClassifiervon scikit-learn wäre die fünfte Zeile in genau diesem Vergleich und folgte derselbenfit/predict-API. - Lineare Algebra: Die Merkmalsmatrix , das
Standardisieren als affine Abbildung je Spalte, das Skalarprodukt im
SVM-Kern — alles direkte Anwendung. NumPys
@-Operator ist die Matrixmultiplikation der Vorlesung. - Stochastik: Stratifiziertes Sampling, der Mittelwert-Schätzer über Falten und seine Standardabweichung sind Schätztheorie. Die Frage „ist der Unterschied echt?” ist im Kern ein Hypothesentest.
- Algorithmen & Datenstrukturen: Hinter den drei API-Methoden stecken sehr unterschiedliche Algorithmen — kNN braucht räumliche Suchstrukturen (k-d-Baum, Ball-Baum), der Entscheidungsbaum ist gierige rekursive Partition, die SVM löst ein quadratisches Optimierungsproblem. Die Estimator-API abstrahiert genau diese Vielfalt weg.
Quellen
- Foliensatz
_345_ML_Python.pdf— Überblick über den Python-ML-Stack: scikit-learn (mit den vier Feldern Classification, Clustering, Data Preparation, Evaluation), die NumPy- und pandas-Cheatsheets von DataCamp sowie Matplotlib und Seaborn zur Visualisierung. Der Satz ist bewusst link-lastig (Verweise auf den scikit-learn-User-Guide,matplotlib.org,seaborn.pydata.org); ich habe ihn als Landkarte genutzt (welche Bibliothek wofür) und die konkrete Estimator-Mechanik darüber hinaus an der Originaldokumentation vertieft, weil Folien hier naturgemäß nur Schlaglichter setzen. - scikit-learn User Guide & API-Referenz — die maßgebliche
Quelle für die
fit/predict/score-Konvention,Pipeline,StratifiedKFoldundcross_val_score. Das berühmte „Classifier comparison”-Beispiel der Galerie war die direkte Vorlage für die Abbildung; ich habe es auf vier Modelle und den Pipeline-/CV-Aufbau zugeschnitten und ausprobiert. - NumPy- und pandas-Dokumentation — für
ndarray-Semantik (dtype, Vektorisierung) undDataFrame-Grundlagen, soweit für die obigen Definitionen nötig. - Russell & Norvig, Artificial Intelligence: A Modern Approach, Kap. 19/20 — als konzeptioneller Hintergrund zu Modellklassen und Generalisierung; die Implementierungssicht ergänzt dort die eher mathematische Darstellung.