Skip to content

11. Machine Learning mit scikit-learn

Die Grundlagen des Machine Learnings verstehen und mit scikit-learn eigene Modelle entwickeln.

Machine Learning gehört heute zu den wichtigsten Anwendungsgebieten von Python. Viele Bibliotheken existieren für diesen Bereich, doch scikit-learn hat sich als Standardwerkzeug für klassische Machine- Learning-Verfahren etabliert.

Die Bibliothek bietet eine einheitliche API für Datenvorbereitung, Modelltraining, Vorhersagen und Evaluation. Dadurch lassen sich viele Verfahren mit vergleichsweise wenig Code einsetzen.

Ziel dieses Kapitels ist nicht die mathematische Herleitung der Algorithmen, sondern das Verständnis des typischen Workflows. Sie lernen, wie Daten vorbereitet, Modelle trainiert und Ergebnisse bewertet werden.

Die vorgestellten Konzepte bilden außerdem die Grundlage für viele fortgeschrittene Verfahren und Frameworks im Bereich künstlicher Intelligenz.

Was ist Machine Learning?

Machine Learning (ML) ist ein Teilgebiet der künstlichen Intelligenz, das Algorithmen entwickelt, die aus Daten lernen, ohne explizit dafür programmiert zu sein. Im Gegensatz zu klassischen Softwarelösungen, bei denen das Verhalten durch fest kodierte Regeln definiert wird, basiert Machine Learning auf statistischen Modellen, die Muster in Daten erkennen und darauf basierende Vorhersagen treffen.

Überwachtes Lernen – der häufigste Ansatz

Das überwachte Lernen (supervised learning) ist die am weitesten verbreitete Form des Machine Learnings. Hierbei stehen sogenannte Trainingsdaten zur Verfügung, die sowohl Eingabedaten (Features) als auch die zugehörigen Zielwerte (Labels) enthalten. Das Ziel ist es, eine Funktion zu finden, die auf Basis der Eingabedaten korrekte Zielwerte vorhersagt.

Ein klassisches Beispiel aus der Webentwicklung ist die Spam-Filterung: E-Mails werden anhand von Merkmalen wie Betreff, Absender oder Textinhalt als "Spam" oder "Nicht-Spam" klassifiziert. Das Modell lernt aus einem annotierten Datensatz, wie es neue E-Mails einordnen kann.

Typische Anwendungsgebiete

Machine Learning findet in vielen Bereichen Anwendung, darunter:

  • Bild- und Spracherkennung: Automatische Klassifikation von Bildern oder Spracheingaben.
  • Empfehlungssysteme: Personalisierte Vorschläge in E-Commerce oder Streamingdiensten.
  • Vorhersagemodelle: Prognosen von Verkaufszahlen, Nutzerverhalten oder Maschinenausfällen.
  • Automatisierung: Intelligente Steuerung von Prozessen und Robotik.

Warum Python für Machine Learning?

Python hat sich als bevorzugte Sprache für Machine Learning etabliert, weil es eine klare, prägnante Syntax bietet, die sich besonders für schnelle Prototypen eignet.

Zudem verfügt Python über ein umfangreiches Ökosystem spezialisierter Bibliotheken wie NumPy für numerische Berechnungen, Pandas für Datenmanipulation und scikit-learn für Machine Learning. Diese Bibliotheken sind gut aufeinander abgestimmt und ermöglichen effiziente Workflows.

Beispiel: Einfaches Klassifikationsmodell in Python

Im Folgenden ein minimalistisches Beispiel, das zeigt, wie man mit scikit-learn ein Modell trainiert, das Iris-Blumenarten klassifiziert:

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

# Daten laden
iris = load_iris()
X, y = iris.data, iris.target

# Daten aufteilen
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Modell instanziieren und trainieren
model = RandomForestClassifier(random_state=42)
model.fit(X_train, y_train)

# Vorhersagen
predictions = model.predict(X_test)

# Genauigkeit ausgeben (1.0 ist die beste Genauigkeit)
print(f"Accuracy: {accuracy_score(y_test, predictions):.2f}")
Accuracy: 1.00

Dieser Code illustriert den typischen Ablauf: Daten laden, aufteilen, Modell erstellen, trainieren und evaluieren.

Der typische Machine-Learning-Workflow

Der typische Machine-Learning-Workflow gliedert sich in mehrere klar definierte Phasen, die systematisch durchlaufen werden, um aus Rohdaten ein belastbares Modell zu entwickeln. Für erfahrene Entwickler ist es wichtig, diesen Ablauf nicht nur als Abfolge von Schritten, sondern als iterativen Prozess zu verstehen, der Flexibilität und Wiederholbarkeit erfordert.

1. Datenakquise und -exploration

Der Ausgangspunkt ist die Sammlung und erste Analyse der Rohdaten. Erste statistische Kennzahlen und Visualisierungen helfen, ein Gefühl für die Daten zu bekommen und potenzielle Probleme wie fehlende Werte oder Ausreißer zu identifizieren.

2. Datenvorbereitung

Hier erfolgt die Bereinigung und Transformation der Daten. Typische Schritte sind das Entfernen oder Imputieren fehlender Werte, das Kodieren kategorialer Variablen und das Skalieren numerischer Merkmale. Python bietet mit scikit-learn und Pandas leistungsfähige Werkzeuge, die sich gut zu Pipelines kombinieren lassen, was den Workflow reproduzierbar und modular gestaltet.

3. Aufteilung in Trainings- und Testdaten

Um eine realistische Einschätzung der Modellqualität zu erhalten, werden die Daten in Trainings- und Testsets aufgeteilt. Dabei gilt es, Datenlecks zu vermeiden, indem keine Informationen aus dem Testset in den Trainingsprozess einfließen.

4. Modellwahl und Training

Basierend auf der Problemstellung (z. B. Klassifikation oder Regression) wird ein geeignetes Modell ausgewählt. Scikit-learn bietet eine einheitliche API, die den Wechsel zwischen Modellen erleichtert – ein Konzept, das in stark typisierten Sprachen oft durch Interfaces oder abstrakte Basisklassen umgesetzt wird. Das Training erfolgt durch Aufruf von fit(), wobei die interne Optimierung meist komplexe Algorithmen kapselt.

5. Evaluation

Nach dem Training wird das Modell anhand des Testsets bewertet. Metriken wie Accuracy, Precision oder RMSE geben Aufschluss über die Leistungsfähigkeit. Anders als in klassischen Softwaretests ist hier das Ergebnis probabilistisch und erfordert Interpretation.

6. Iteration und Optimierung

Basierend auf der Evaluation werden Parameter angepasst, Features verändert oder sogar andere Modelle ausprobiert. Python-Pipelines und Grid Search erleichtern diese Iterationen erheblich, da sie Konfigurationsänderungen und Wiederholbarkeit unterstützen.

7. Deployment und Monitoring

Das finale Modell wird in eine produktive Umgebung überführt. Hier zeigt sich oft der Unterschied zu klassischen Anwendungen: Machine-Learning-Modelle benötigen kontinuierliches Monitoring und gelegentliches Retraining, um ihre Qualität zu erhalten.

Beispiel: Workflow-Skizze mit scikit-learn

import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import Pipeline
from sklearn.metrics import accuracy_score

# Daten laden
data: pd.DataFrame = pd.read_csv('user_data.csv')
X = data.drop(columns=['target'])
y = data['target']

# Aufteilung
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Pipeline definieren
pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('classifier', LogisticRegression(max_iter=1000))
])

# Training
pipeline.fit(X_train, y_train)

# Vorhersage
y_pred = pipeline.predict(X_test)

# Evaluation
print(f'Accuracy: {accuracy_score(y_test, y_pred):.3f}')

Diese Struktur zeigt, wie Python-Idiome und scikit-learn-APIs zusammenwirken, um den Workflow klar, modular und reproduzierbar zu gestalten.

Merksatz

Ein erfolgreicher Machine-Learning-Workflow ist kein linearer Prozess, sondern ein iterativer Zyklus aus Datenverständnis, Modelltraining und Evaluation – Python und scikit-learn bieten hierfür eine flexible und expressive Plattform, die sich gut an professionelle Entwicklungsprozesse anpasst.

Trainings- und Testdaten

Beim maschinellen Lernen ist die korrekte Aufteilung der Daten in Trainings- und Testsets essenziell, um die Generalisierbarkeit eines Modells realistisch beurteilen zu können. Anders als in typischen Softwaretests, bei denen man oft deterministisch und isoliert einzelne Komponenten prüft, geht es hier darum, ein Modell auf historischen Daten zu trainieren und anschließend auf bisher ungesehenen Daten zu validieren.

Warum Trainings- und Testdaten aufteilen?

Das Ziel ist, Overfitting zu vermeiden: Ein Modell, das zu stark an den Trainingsdaten haftet, liefert auf neuen Daten schlechte Vorhersagen. Die Aufteilung stellt sicher, dass das Modell nicht einfach nur die Trainingsbeispiele auswendig lernt, sondern Muster erkennt, die auch auf unbekannte Daten anwendbar sind.

Standardverfahren mit scikit-learn

In Python ist die Funktion train_test_split aus sklearn.model_selection der idiomatische Weg, um Datensätze aufzuteilen. Sie bietet neben der Aufteilung auch Optionen zur Reproduzierbarkeit und zum stratified Sampling.

from sklearn.model_selection import train_test_split
import pandas as pd

# Beispiel: Daten aus einer CSV-Datei laden
data = pd.read_csv('user_logs.csv')

# Features und Zielvariable extrahieren
X = data.drop(columns=['churn'])  # Eingabedaten
y = data['churn']  # Zielvariable

# Aufteilen mit festem Zufallssamen für Reproduzierbarkeit
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

Parameter im Detail

  • test_size=0.2: 20 % der Daten werden als Testset reserviert.
  • random_state=42: Fixiert den Zufallsstart, damit die Aufteilung reproduzierbar bleibt.
  • stratify=y: Sorgt dafür, dass die Klassenverteilung im Trainings- und Testset erhalten bleibt – besonders wichtig bei unbalancierten Daten.

Datenlecks vermeiden

Ein häufiger Fehler, gerade bei Umsteigern aus statisch typisierten Sprachen, ist es, die Datenaufteilung zu spät oder inkorrekt durchzuführen. Beispielsweise sollten Vorverarbeitungsschritte wie Skalierung oder Feature-Engineering nur auf dem Trainingsset gelernt und dann auf das Testset angewendet werden. Wenn man zuerst die Daten transformiert und dann teilt, können Informationen aus dem Testset in das Training einfließen – ein klassisches Datenleck.

Best Practices

  • Immer random_state setzen, um Experimente vergleichbar zu machen.
  • Bei Klassifikationsproblemen stratify verwenden, um Klassenverteilung zu erhalten.
  • Vorverarbeitung strikt nach der Aufteilung durchführen, um Datenlecks zu vermeiden.
  • Für kleine Datensätze Cross-Validation in Betracht ziehen (siehe späteres Kapitel).

Zusammenfassung

Die Aufteilung in Trainings- und Testdaten ist der erste, aber kritische Schritt, um valide Machine-Learning-Modelle zu entwickeln. Python und scikit-learn liefern dafür eine elegante, gut lesbare API, die sich an bewährten Prinzipien orientiert und typische Fehlerquellen minimiert.

Features und Zielvariablen

Merkmale (Features) und Zielvariable (Target Variable)

Im Machine Learning sind Features die Eingabedaten, anhand derer ein Modell Muster lernt, während die Zielvariable die vorherzusagende Größe darstellt. In Python repräsentieren Features typischerweise eine Tabelle (DataFrame), in der jede Zeile ein Beispiel und jede Spalte ein Merkmal ist. Die Zielvariable ist meist eine einzelne Spalte oder ein Array.

Auswahl und Vorbereitung von Features

Nicht alle verfügbaren Daten sind automatisch nützlich. Features sollten informativ, nicht redundant und möglichst unabhängig voneinander sein. Typische Schritte:

  • Relevanz prüfen: Korrelationen oder andere statistische Maße helfen, wichtige Merkmale zu identifizieren.
  • Typen beachten: Numerische, kategoriale oder zeitliche Daten erfordern unterschiedliche Behandlung.
  • Feature-Engineering: Neue Features aus bestehenden ableiten, z. B. Zeitdifferenzen oder Aggregationen.

Python bietet mit Pandas und NumPy effiziente Werkzeuge, um diese Transformationen idiomatisch umzusetzen:

import pandas as pd

# Beispiel: Neue Feature-Spalte aus Datum ableiten
sales = pd.DataFrame({
    'date': pd.to_datetime(['2023-01-01', '2023-01-02']),
    'revenue': [100, 150]
})
sales['day_of_week'] = sales['date'].dt.dayofweek

Zielvariable definieren

Die Zielvariable ist der Grund, warum wir überhaupt ein Modell trainieren. Sie kann kategorisch (Klassifikation) oder numerisch (Regression) sein. Wichtig ist, dass sie sauber und konsistent vorliegt. Fehlende Werte oder inkonsistente Labels müssen vor dem Training bereinigt werden.

In Python trennt man Features und Zielvariable meist explizit:

X = df.drop(columns=['target'])  # Features
y = df['target']                 # Zielvariable

Typische Stolperfallen und Unterschiede zu Java/C

  • Mutabilität und Kopien: Pandas operiert häufig mit Views statt Kopien. Änderungen an Features können unerwartet den Originaldatensatz beeinflussen. Explizites Kopieren (df.copy()) ist oft sinnvoll.

  • Dynamische Typisierung: Im Gegensatz zu statisch typisierten Sprachen sind Feature-Spalten heterogen. Typen sollten vor Modelltraining geprüft und ggf. konvertiert werden.

Best Practices

  • Nutze Pandas für übersichtliche, tabellarische Datenbearbeitung.
  • Trenne Features und Zielvariable klar, um Fehler zu vermeiden.
  • Prüfe und konvertiere Datentypen vor Modelltraining.
  • Verwende aussagekräftige Feature-Namen, um Code lesbar zu halten.

Beispiel: Vorbereitung eines Datensatzes für ein Klassifikationsproblem

import pandas as pd
from sklearn.model_selection import train_test_split

# Beispiel-Daten laden
users = pd.DataFrame({
    'age': [25, 32, 47, 51],
    'gender': ['M', 'F', 'F', 'M'],
    'signup_days_ago': [100, 200, 300, 400],
    'churned': [0, 1, 0, 1]  # Zielvariable
})

# Kategoriale Merkmale kodieren
users['gender_encoded'] = users['gender'].map({'M': 0, 'F': 1})

# Features und Ziel definieren
X = users[['age', 'signup_days_ago', 'gender_encoded']]
y = users['churned']

# Aufteilen in Trainings- und Testdaten
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

In diesem Beispiel wird ein kategoriales Feature explizit in numerische Werte transformiert, was in Python mit Pandas sehr direkt möglich ist.

Vorverarbeitung von Daten

Warum Vorverarbeitung wichtig ist

Machine Learning-Modelle erwarten oft numerische Eingaben in einem bestimmten Wertebereich oder Verteilung. Rohdaten aus realen Anwendungen sind selten optimal formatiert: Sie können unterschiedliche Skalen, fehlende Werte oder kategoriale Merkmale enthalten. Die Vorverarbeitung bereitet diese Daten so auf, dass Modelle effizient und robust trainiert werden können.

Skalierung und Normalisierung

Viele Algorithmen (z.B. k-NN, SVM, neuronale Netze) sind empfindlich gegenüber der Skala der Features. Unterschiedliche Größenordnungen können das Training verzerren und die Konvergenz verlangsamen.

Die gängigsten Verfahren sind:

  • Min-Max-Skalierung: Transformiert Werte auf einen festen Bereich, meist [0, 1].
  • Standardisierung: Zieht den Mittelwert ab und teilt durch die Standardabweichung, sodass die Verteilung Mittelwert 0 und Varianz 1 hat.
  • Robuste Skalierung: Nutzt Median und Interquartilsabstand, um Ausreißer weniger stark zu beeinflussen.
from sklearn.preprocessing import StandardScaler, MinMaxScaler, RobustScaler
import numpy as np

# Beispiel-Daten aus einer Webanwendung
data = np.array([[100, 0.001], [200, 0.003], [300, 0.002], [400, 0.005]])

scaler = StandardScaler()
data_scaled = scaler.fit_transform(data)
print(data_scaled)

[[-1.34164079 -1.18321596]
 [-0.4472136   0.16903085]
 [ 0.4472136  -0.50709255]
 [ 1.34164079  1.52127766]]
Die erste Spalte (100–400) und die zweite Spalte (0.001–0.005) werden dabei jeweils auf Mittelwert 0 und Standardabweichung 1 skaliert.

Umgang mit kategorialen Merkmalen

Im Gegensatz zu statisch typisierten Sprachen, wo Enums oder Klassenhierarchien oft zur Modellierung kategorialer Daten verwendet werden, ist in Python mit scikit-learn die One-Hot-Encoding-Strategie Standard. Dabei wird jede Kategorie in eine binäre Spalte umgewandelt.

from sklearn.preprocessing import OneHotEncoder
import numpy as np

categories = np.array([['red'], ['green'], ['blue'], ['green']])
encoder = OneHotEncoder(sparse=False)
categories_encoded = encoder.fit_transform(categories)
print(categories_encoded)
[[0. 0. 1.]
 [0. 1. 0.]
 [1. 0. 0.]
 [0. 1. 0.]]

Pipeline für reproduzierbare Vorverarbeitung

Python-typisch werden Vorverarbeitungsschritte in einer Pipeline kombiniert, die sowohl Skalierung als auch Kodierung und Modelltraining kapselt. Das erleichtert sauberes, wartbares und testbares Machine Learning.

from sklearn.pipeline import Pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder, StandardScaler
import pandas as pd

# Beispiel-Daten
X = pd.DataFrame({
    'age': [25, 32, 47, 51],
    'income': [50000, 60000, 80000, 90000],
    'gender': ['male', 'female', 'female', 'male']
})
y = [0, 1, 0, 1]

# Vorverarbeitung
numeric_features = ['age', 'income']
numeric_transformer = StandardScaler()

categorical_features = ['gender']
categorical_transformer = OneHotEncoder()

preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, numeric_features),
        ('cat', categorical_transformer, categorical_features)
    ])

pipeline = Pipeline(steps=[('preprocessor', preprocessor),
                           ('classifier', LogisticRegression())])

pipeline.fit(X, y)

Best Practices und Fallstricke

  • Datenlecks vermeiden: Skalierer und Encoder immer nur mit Trainingsdaten fitten, dann auf Testdaten transformieren.
  • Pipeline verwenden: So vermeidet man Fehler und hält Code übersichtlich.
  • Ausreißer beachten: RobustScaler kann helfen, wenn Daten stark verzerrt sind.
  • Feature Engineering: Vorverarbeitung ist mehr als Skalieren – Merkmalsauswahl und -erzeugung sind oft entscheidend.

Arbeiten mit Pipelines

In Machine-Learning-Projekten ist die Kombination von Datenvorverarbeitung und Modelltraining ein zentraler Schritt. scikit-learn bietet mit Pipeline eine elegante Möglichkeit, diese Schritte zu einem reproduzierbaren Workflow zusammenzufassen. Dies entspricht dem Prinzip der Komposition, das in objektorientierten Sprachen wie Java oder C# häufig durch Builder oder Fluent Interfaces umgesetzt wird. In Python ist die Pipeline ein klar definierter, serialisierbarer Ablauf, der Vorverarbeitung und Modelltraining eng koppelt.

Warum Pipelines?

Ohne Pipeline muss man Vorverarbeitung und Modelltraining manuell koordinieren. Das führt leicht zu Fehlern, z.B. wenn man bei der Vorhersage vergisst, die gleichen Transformationen anzuwenden. Außerdem erschwert es die Wiederverwendbarkeit und Testbarkeit. Pipelines kapseln diese Logik und gewährleisten, dass alle Schritte konsistent ausgeführt werden.

Aufbau einer Pipeline

Eine Pipeline ist eine Liste von benannten Schritten, die nacheinander ausgeführt werden. Jeder Schritt außer dem letzten muss ein Transformer sein (d.h. ein Objekt mit fit und transform Methoden). Der letzte Schritt ist ein Estimator (z.B. ein Klassifikator oder Regressor), der fit und predict unterstützt.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression

pipeline = Pipeline([
    ('scaler', StandardScaler()),  # Vorverarbeitung
    ('clf', LogisticRegression(max_iter=1000))  # Modell
])

Nutzung der Pipeline

Die Pipeline verhält sich wie ein normaler Estimator. fit trainiert alle Schritte, predict führt die Vorverarbeitung und Vorhersage durch.

X_train, X_test, y_train, y_test = ...  # Annahme: Datensatz ist vorbereitet
pipeline.fit(X_train, y_train)
predictions = pipeline.predict(X_test)

Vorteile gegenüber separater Behandlung

  • Konsistenz: Transformationen werden immer in der gleichen Reihenfolge und mit den gleichen Parametern angewandt.
  • Reproduzierbarkeit: Die Pipeline kann als Ganzes serialisiert (z.B. mit joblib) und später wiederverwendet werden.
  • Integration: Pipelines lassen sich nahtlos in Cross-Validation, Grid-Search und andere scikit-learn-Utilities einbinden.

Beispiel: Pipeline mit Feature-Engineering

In der Praxis kann eine Pipeline mehrere Vorverarbeitungsschritte enthalten, z.B. Skalierung, Encoding und Feature-Auswahl.

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.feature_selection import SelectKBest, f_classif

numeric_features = ['age', 'income']
categorical_features = ['gender', 'city']

preprocessor = ColumnTransformer([
    ('num', StandardScaler(), numeric_features),
    ('cat', OneHotEncoder(handle_unknown='ignore'), categorical_features)
])

pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('feature_selection', SelectKBest(score_func=f_classif, k=10)),
    ('classifier', LogisticRegression(max_iter=1000))
])

pipeline.fit(X_train, y_train)

Best Practices

  • Verwenden Sie sprechende Namen für Pipeline-Schritte, um die Lesbarkeit zu erhöhen.
  • Nutzen Sie Pipelines immer in Kombination mit Cross-Validation, um Datenlecks zu vermeiden.
  • Serialisieren Sie die gesamte Pipeline, nicht nur das Modell, um Vorverarbeitungsschritte zu bewahren.

Merksatz

Pipelines sind der idiomatische Weg in Python, um Vorverarbeitung und Modelltraining sicher, reproduzierbar und wartbar zu verbinden.

Erste Klassifikation

Klassifikation mit scikit-learn

Das Ziel der Klassifikation ist es, Eingabedaten einer von mehreren diskreten Klassen zuzuordnen. In Python ist scikit-learn das zentrale Framework für Machine Learning, das durch seine konsistente API und umfangreiche Modellbibliothek besticht. Das Arbeiten mit scikit-learn ist sehr pragmatisch: Modelle sind Objekte, die fit- und predict-Methoden implementieren, was den Workflow stark vereinfacht.

Ein einfaches Klassifikationsbeispiel

Wir verwenden den bekannten Iris-Datensatz, der in scikit-learn eingebaut ist. Ziel ist es, die Pflanzenart anhand von vier Merkmalen zu klassifizieren.

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import classification_report

# Daten laden
iris = load_iris()
X, y = iris.data, iris.target

# Daten aufteilen: 80% Training, 20% Test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Modell initialisieren
model = RandomForestClassifier(random_state=42)

# Modell trainieren
model.fit(X_train, y_train)

# Vorhersagen erzeugen
y_pred = model.predict(X_test)

# Ergebnis ausgeben
print(classification_report(y_test, y_pred, target_names=iris.target_names))
              precision    recall  f1-score   support

      setosa       1.00      1.00      1.00        10
  versicolor       1.00      1.00      1.00         9
   virginica       1.00      1.00      1.00        11

    accuracy                           1.00        30
   macro avg       1.00      1.00      1.00        30
weighted avg       1.00      1.00      1.00        30

Die fit-Methode entspricht dem Training, predict erzeugt Vorhersagen für neue Daten. Die Trennung von Training und Vorhersage ist klar und entspricht dem Konzept von fit und predict in scikit-learn.

Warum RandomForestClassifier?

Random Forests sind robuste, nichtlineare Modelle, die gut mit heterogenen Daten umgehen können und wenig Hyperparameter-Tuning benötigen. Für den Einstieg ist das ein guter Kompromiss zwischen Einfachheit und Leistungsfähigkeit.

  • Einfache Pipeline: scikit-learn-Modelle sind austauschbar, da sie einheitliche Methoden besitzen. So kann man z.B. später leicht andere Klassifikatoren ausprobieren, ohne die restliche Pipeline zu ändern.

Best Practices

  • Random State setzen: Für reproduzierbare Ergebnisse immer random_state setzen, da viele Modelle intern Zufall verwenden.

  • Train-Test-Split: Niemals die Testdaten während des Trainings verwenden, um Overfitting zu vermeiden.

  • Modellbewertung: Nutze Metriken wie Precision, Recall und F1-Score, um die Qualität der Klassifikation umfassend zu beurteilen (siehe spätere Abschnitte).

Zusammenfassung

Die ersten Schritte mit scikit-learn sind bewusst simpel gehalten: Modell initialisieren, mit Trainingsdaten trainieren, Vorhersagen erzeugen. Die klare Trennung von Daten, Modell und Vorhersage sowie die einheitliche API erleichtern den Umstieg von klassisch objektorientierten Sprachen auf Python erheblich.

Bewertung von Klassifikationsmodellen

Grundlegende Metriken zur Bewertung von Klassifikationsmodellen

Im Machine Learning ist die Bewertung von Klassifikationsmodellen essenziell, um die Qualität der Vorhersagen zu beurteilen. Die wichtigsten Metriken sind Accuracy, Precision, Recall und F1-Score.

Accuracy – Anteil korrekter Vorhersagen

Accuracy ist der Anteil der korrekt klassifizierten Beispiele an allen Beispielen. Sie ist intuitiv und einfach zu interpretieren, eignet sich aber nur, wenn die Klassen ausgewogen verteilt sind.

from sklearn.metrics import accuracy_score

y_true = [0, 1, 0, 1, 1]
y_pred = [0, 0, 0, 1, 1]

acc = accuracy_score(y_true, y_pred)
print(f"Accuracy: {acc:.2f}")

Precision und Recall – Fokus auf Klassen

Precision misst, wie viele der als positiv klassifizierten Beispiele tatsächlich positiv sind. Recall misst, wie viele der tatsächlichen Positiven korrekt erkannt wurden. Diese Metriken sind besonders wichtig bei unausgewogenen Klassen oder wenn Fehlklassifikationen unterschiedliche Kosten haben.

from sklearn.metrics import precision_score, recall_score

precision = precision_score(y_true, y_pred)
recall = recall_score(y_true, y_pred)
print(f"Precision: {precision:.2f}, Recall: {recall:.2f}")

Diese Funktionen unterstützen auch die Angabe von Parametern wie pos_label oder average, was in Python durch optionale Parameter elegant gelöst wird.

F1-Score – Harmonic Mean von Precision und Recall

Der F1-Score fasst Precision und Recall zu einer einzigen Metrik zusammen und ist besonders nützlich, wenn ein ausgewogenes Verhältnis zwischen beiden wichtig ist.

from sklearn.metrics import f1_score

f1 = f1_score(y_true, y_pred)
print(f"F1-Score: {f1:.2f}")

Best Practices

  • Verwende scikit-learn-Metriken direkt: Sie sind gut getestet, performant und unterstützen viele Optionen.
  • Beachte das Klassenungleichgewicht: Accuracy kann irreführend sein, wenn eine Klasse dominiert.
  • Verwende den F1-Score bei unbalancierten Klassen: Er bietet eine robustere Bewertung.
  • Nutze classification_report für eine Übersicht:
from sklearn.metrics import classification_report

print(classification_report(y_true, y_pred))

Dieser Bericht liefert alle wichtigen Metriken auf einen Blick und ist ein Python-idiomatischer Weg, um umfassende Bewertungen zu erhalten.

Zusammenfassung

Die Bewertung von Klassifikationsmodellen in Python ist dank scikit-learn prägnant und klar strukturiert. Die Metriken Accuracy, Precision, Recall und F1-Score sind essenziell, um verschiedene Aspekte der Modellqualität zu verstehen. Python fördert durch seine Bibliotheken einen Ausdrucksstil, der sich auf die Analyse konzentriert und weniger auf die Implementierungsdetails.

Die Confusion Matrix

Die Confusion Matrix ist ein zentrales Werkzeug zur detaillierten Analyse der Vorhersageergebnisse von Klassifikationsmodellen. Während einfache Metriken wie Accuracy einen schnellen Überblick bieten, zeigt die Confusion Matrix, wie gut das Modell in den einzelnen Klassen unterscheidet und wo typische Fehler auftreten.

Aufbau und Interpretation

Eine Confusion Matrix ist eine quadratische Matrix, deren Dimension der Anzahl der Klassen entspricht. Für eine binäre Klassifikation enthält sie vier Felder:

  • True Positives (TP): Korrekt als positiv klassifizierte Beispiele
  • True Negatives (TN): Korrekt als negativ klassifizierte Beispiele
  • False Positives (FP): Fälschlich als positiv klassifizierte Beispiele (Typ-I-Fehler)
  • False Negatives (FN): Fälschlich als negativ klassifizierte Beispiele (Typ-II-Fehler)

Diese Werte erlauben eine differenzierte Bewertung, die über die reine Trefferquote hinausgeht.

Beispiel in Python mit scikit-learn

from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
import matplotlib.pyplot as plt
import numpy as np

# Beispielhafte Vorhersagen und wahre Labels
y_true: list[int] = [0, 1, 0, 1, 0, 1, 1, 0]
y_pred: list[int] = [0, 0, 0, 1, 0, 1, 0, 1]

# Berechnung der Confusion Matrix
cm: np.ndarray = confusion_matrix(y_true, y_pred)
print("Confusion Matrix:\n", cm)

# Visualisierung
disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=["Klasse 0", "Klasse 1"])
disp.plot(cmap="Blues")
plt.show()

Confusion-Matrix

Die Ausgabe zeigt die Anzahl der korrekten und falschen Klassifikationen pro Klasse. Die Visualisierung erleichtert die Interpretation, insbesondere bei mehr als zwei Klassen.

Typische Fehlerquellen erkennen

  • Unbalancierte Klassen: Eine hohe Anzahl von TN kann die Accuracy verzerren, obwohl das Modell die Minderheitsklasse schlecht erkennt.
  • False Positives vs. False Negatives: Je nach Anwendung (z. B. Betrugserkennung vs. medizinische Diagnostik) sind unterschiedliche Fehlerarten kritischer.

Best Practices

  • Nutze ConfusionMatrixDisplay für klare Visualisierungen.
  • Analysiere die Matrix immer im Kontext der Domäne, um Fehlertypen richtig zu gewichten.
  • Ergänze die Confusion Matrix mit Metriken wie Precision, Recall und F1-Score für eine umfassende Bewertung.

Merksatz

Die Confusion Matrix zeigt nicht nur, wie viele Fehler ein Modell macht, sondern welche Fehler – und das ist entscheidend für gezielte Verbesserungen.

Erste Regression

Die Regression ist ein zentraler Bestandteil des Machine Learnings, wenn es darum geht, numerische Zielwerte vorherzusagen. Im Gegensatz zur Klassifikation, bei der diskrete Klassen vorhergesagt werden, modellieren Regressionsverfahren kontinuierliche Werte, beispielsweise Preise, Temperaturen oder Messgrößen.

Lineare Regression mit scikit-learn

Die lineare Regression ist das einfachste und zugleich am häufigsten eingesetzte Regressionsmodell. Es modelliert die Zielvariable als lineare Kombination der Eingabemerkmale. In Python mit scikit-learn ist die Anwendung sehr direkt und folgt dem bekannten Fit-Predict-Paradigma:

import numpy as np
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Beispiel: Vorhersage von Immobilienpreisen
# Realistische Features: Wohnfläche, Zimmeranzahl, Baujahr

data = pd.DataFrame({
    'living_area': [50, 60, 70, 80, 90],
    'rooms': [2, 3, 3, 4, 4],
    'year_built': [1990, 1985, 2000, 2010, 2015],
    'price': [150000, 180000, 200000, 230000, 250000]
})

X = data[['living_area', 'rooms', 'year_built']]
y = data['price']

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)

model = LinearRegression()
model.fit(X_train, y_train)

y_pred = model.predict(X_test)

mse = mean_squared_error(y_test, y_pred)
print(f"Mean Squared Error: {mse:.2f}")

Die LinearRegression-Klasse schätzt die Koeffizienten der linearen Funktion mittels der Methode der kleinsten Quadrate. Das Modell ist interpretierbar, da die Koeffizienten direkt den Einfluss der einzelnen Features auf die Zielvariable beschreiben.

Datenvorbereitung und Feature Engineering

Auch bei Regression ist die sorgfältige Vorbereitung der Features entscheidend. Skalierung (z.B. Standardisierung) kann die Konvergenz verbessern, vor allem bei Modellen wie Ridge oder Lasso. Kategorische Variablen müssen kodiert werden (One-Hot-Encoding).

from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline

numeric_features = ['living_area', 'year_built']
categorical_features = ['rooms']

preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), numeric_features),
        ('cat', OneHotEncoder(), categorical_features)
    ]
)

pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('regressor', LinearRegression())
])

pipeline.fit(X_train, y_train)
y_pred = pipeline.predict(X_test)

mse = mean_squared_error(y_test, y_pred)
print(f"MSE with preprocessing: {mse:.2f}")

Diese Pipeline kombiniert Vorverarbeitung und Modelltraining zu einem reproduzierbaren Workflow. Das ist in Python mit scikit-learn besonders elegant, da die API konsistent und deklarativ ist.

Erweiterte Regressionsmodelle

Neben der linearen Regression gibt es viele weitere Modelle, die nichtlineare Zusammenhänge erfassen können, z.B. Entscheidungsbäume, Random Forests oder Gradient Boosting. Diese Modelle sind in scikit-learn ebenfalls einfach zu verwenden und folgen dem gleichen Fit-Predict-Muster.

Zusammenfassung

  • Regression sagt kontinuierliche Werte voraus, anders als Klassifikation.
  • Die lineare Regression ist ein guter Einstieg und leicht interpretierbar.
  • Python und scikit-learn ermöglichen durch konsistente APIs und Pipelines effiziente und wartbare Workflows.
  • Vorverarbeitung ist auch bei Regression essenziell.
  • Erweiterte Modelle können komplexe Zusammenhänge abbilden, ohne die API zu verändern.

Lineare-Regression

Modelle vergleichen

Modelle vergleichen: Auswahl basierend auf Metriken und Kontext

In der Praxis steht man selten vor der Wahl eines einzelnen Machine-Learning-Modells. Stattdessen ist es üblich, mehrere Modelle zu trainieren und deren Leistung systematisch zu vergleichen.

Wichtige Vergleichskriterien

Der Vergleich von Modellen erfolgt meist anhand von Metriken, die zur Problemstellung passen:

  • Klassifikation: Accuracy, Precision, Recall, F1-Score, ROC-AUC
  • Regression: MAE, MSE, RMSE, R²

Es ist entscheidend, die Metriken im Kontext der Domäne zu interpretieren. Beispielsweise kann bei unbalancierten Klassen die Accuracy irreführend sein.

Beispiel: Vergleich von Klassifikationsmodellen

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.svm import SVC
from sklearn.metrics import classification_report

# Datensatz laden
X, y = fetch_openml(
    "adult",
    version=2,
    as_frame=True,
    return_X_y=True
)

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    stratify=y,
    random_state=42
)

# Numerische und kategoriale Spalten
num_cols = X.select_dtypes(include=["int64", "float64"]).columns
cat_cols = X.select_dtypes(include=["object", "category"]).columns

# Vorverarbeitung
preprocessor = ColumnTransformer(
    transformers=[
        ("num", StandardScaler(), num_cols),
        ("cat", OneHotEncoder(handle_unknown="ignore"), cat_cols),
    ]
)

# Modelle
models = {
    "Logistic Regression": LogisticRegression(
        max_iter=1000,
        random_state=42
    ),
    "Random Forest": RandomForestClassifier(
        n_estimators=100,
        random_state=42
    ),
    "SVM": SVC(
        kernel="rbf",
        random_state=42
    ),
}

# Training + Evaluation
for name, estimator in models.items():

    pipeline = Pipeline(
        steps=[
            ("preprocessing", preprocessor),
            ("model", estimator),
        ]
    )

    pipeline.fit(X_train, y_train)

    y_pred = pipeline.predict(X_test)

    print(f"\n--- {name} ---")
    print(classification_report(y_test, y_pred, zero_division=0))
--- Logistic Regression ---

              precision    recall  f1-score   support

       <=50K       0.88      0.93      0.91      9289
        >50K       0.74      0.59      0.66      2922

    accuracy                           0.85     12211
   macro avg       0.81      0.76      0.78     12211
weighted avg       0.85      0.85      0.85     12211

Dieses Vorgehen zeigt die Einfachheit, mit der in Python mehrere Modelle verglichen werden können: Das einheitliche API erlaubt es, Modelle in Collections zu verwalten und iterativ zu trainieren und zu evaluieren.

Automatisierung mit Cross-Validation

Um robuste Vergleiche zu erzielen, empfiehlt sich Cross-Validation. scikit-learn bietet dafür Funktionen wie cross_val_score oder cross_validate:

from sklearn.model_selection import cross_val_score

for name, model in models.items():
    scores = cross_val_score(model, X_train_scaled, y_train, cv=5, scoring='f1_macro')
    print(f'{name}: Mean F1-Score = {scores.mean():.3f} ± {scores.std():.3f}')

Dies reduziert die Gefahr, ein Modell nur zufällig gut auf einer bestimmten Testpartition zu beurteilen.

Best Practices und Python-spezifische Überlegungen

  • Pipeline-Nutzung: Kombinieren Sie Vorverarbeitung und Modell in einer Pipeline, um Datenlecks zu vermeiden und den Vergleich fair zu gestalten.
  • Modellparameter: Achten Sie darauf, dass alle Modelle mit vergleichbaren Parametern (z.B. Zufallszustand) initialisiert werden, um reproduzierbare Ergebnisse zu gewährleisten.
  • Interpretierbarkeit: Neben reiner Performance kann auch die Interpretierbarkeit ein Auswahlkriterium sein. Python-Tools wie SHAP oder LIME können hier unterstützen.

Zusammenfassung

Der Vergleich mehrerer Modelle in Python profitiert stark von scikit-learns konsistentem API und der Flexibilität von Python-Collections und Iterationen. Im Gegensatz zu typisierten Sprachen ist hier weniger Boilerplate nötig, was den Fokus auf die Analyse und Interpretation der Ergebnisse lenkt. Die Wahl des besten Modells hängt nicht nur von Metriken ab, sondern auch von Kontext, Interpretierbarkeit und Wartbarkeit.

Overfitting und Underfitting

Overfitting und Underfitting sind zentrale Herausforderungen beim Training von Machine-Learning-Modellen. Sie beschreiben zwei gegensätzliche Probleme, die die Generalisierungsfähigkeit eines Modells beeinträchtigen.

Overfitting: Zu genau auf Trainingsdaten angepasst

Overfitting tritt auf, wenn ein Modell die Trainingsdaten zu genau lernt, inklusive Rauschen und Ausreißern. Das Modell passt sich an Details an, die keine allgemeingültigen Muster darstellen, und verliert dadurch die Fähigkeit, auf neuen, unbekannten Daten zuverlässige Vorhersagen zu treffen.

Typische Anzeichen für Overfitting:

  • Sehr niedriger Trainingsfehler, aber hoher Fehler auf Testdaten
  • Große Diskrepanz zwischen Trainings- und Validierungsmetriken

Underfitting: Modell zu einfach

Underfitting entsteht, wenn ein Modell nicht komplex genug ist, um die zugrundeliegenden Muster in den Daten zu erfassen. Dies führt dazu, dass sowohl Trainings- als auch Testfehler hoch sind.

Beispiel: Polynomial Regression

import numpy as np
import matplotlib.pyplot as plt
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

# Daten simulieren: y = 0.5 * x^2 + Rauschen
np.random.seed(42)
x = np.linspace(-3, 3, 100)
y = 0.5 * x ** 2 + np.random.normal(scale=1.0, size=x.shape)

X = x.reshape(-1, 1)

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# Modelle mit unterschiedlichen Komplexitäten
models = {
    "Underfitting (Degree 1)": make_pipeline(PolynomialFeatures(degree=1), LinearRegression()),
    "Good fit (Degree 2)": make_pipeline(PolynomialFeatures(degree=2), LinearRegression()),
    "Overfitting (Degree 10)": make_pipeline(PolynomialFeatures(degree=10), LinearRegression()),
}

for name, model in models.items():
    model.fit(X_train, y_train)
    y_train_pred = model.predict(X_train)
    y_test_pred = model.predict(X_test)
    train_error = mean_squared_error(y_train, y_train_pred)
    test_error = mean_squared_error(y_test, y_test_pred)
    print(f"{name}: Train MSE={train_error:.2f}, Test MSE={test_error:.2f}")

# Visualisierung
plt.scatter(X_train, y_train, color='black', label='Train Data')
X_plot = np.linspace(-3, 3, 100).reshape(-1, 1)
for name, model in models.items():
    y_plot = model.predict(X_plot)
    plt.plot(X_plot, y_plot, label=name)
plt.legend()
plt.title("Polynomial Regression: Underfitting vs Overfitting")
plt.xlabel("x")
plt.ylabel("y")
plt.show()

Dieses Beispiel zeigt, wie ein zu einfaches Modell (Grad 1) die Daten nicht gut erfasst (Underfitting), während ein zu komplexes Modell (Grad 10) die Trainingsdaten fast perfekt abbildet, aber auf Testdaten schlechter performt (Overfitting). Das Modell mit Polynomgrad 2 stellt einen guten Kompromiss dar.

Underfitting-Overfitting

Best Practices zur Vermeidung

  • Datenaufteilung: Immer Trainings- und Testdaten strikt trennen, um Datenlecks zu vermeiden.
  • Cross-Validation: Nutze k-fache Kreuzvalidierung, um die Stabilität des Modells zu prüfen.
  • Regularisierung: Methoden wie Ridge oder Lasso (in scikit-learn) begrenzen Modellkomplexität.
  • Feature-Auswahl: Relevante Merkmale auswählen, irrelevante entfernen.
  • Modellkomplexität anpassen: Beginne mit einfachen Modellen und erhöhe Komplexität schrittweise.

Cross Validation

Grundprinzip der k-fachen Cross Validation

Die Idee hinter k-facher Cross Validation ist, den Datensatz in k gleich große Teilmengen (Folds) aufzuteilen. Das Modell wird k-mal trainiert und getestet:

  • In jedem Durchlauf wird ein Fold als Testset verwendet.
  • Die restlichen k-1 Folds dienen als Trainingsdaten.
  • Die Leistung wird über alle k Durchläufe gemittelt.

Dadurch wird jeder Datenpunkt einmal zum Testen genutzt, was die Varianz der Bewertung reduziert.

Umsetzung mit scikit-learn

scikit-learn bietet mit cross_val_score eine einfache Möglichkeit, Cross Validation durchzuführen. Das folgende Beispiel zeigt, wie ein RandomForestClassifier mit 5-facher CV bewertet wird:

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import fetch_openml
from sklearn.model_selection import cross_val_score

# Beispiel: Klassifikation von Kreditkartenbetrug
X, y = fetch_openml(name='credit-g', version=1, as_frame=True, return_X_y=True)

model = RandomForestClassifier(random_state=42)
scores = cross_val_score(model, X, y, cv=5, scoring='accuracy')

print(f"Cross Validation Accuracy Scores: {scores}")
print(f"Mean Accuracy: {scores.mean():.3f} ± {scores.std():.3f}")

Die Ausgabe liefert eine Liste von Genauigkeiten für jeden Fold sowie den Mittelwert und die Standardabweichung. Diese Streuung gibt Aufschluss über die Stabilität des Modells.

Stratified Cross Validation

Bei Klassifikationsproblemen mit unbalancierten Klassen ist es wichtig, dass jeder Fold die Klassenverteilung des Gesamtdatensatzes widerspiegelt. StratifiedKFold sorgt dafür, dass die Anteile der Klassen in jedem Fold ähnlich sind. cross_val_score verwendet standardmäßig stratified folds bei Klassifikationsmodellen.

Cross Validation für Regressionsmodelle

Für Regressionen bietet scikit-learn KFold, da Stratification hier nicht sinnvoll ist. Beispiel:

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold, cross_val_score
from sklearn.datasets import fetch_california_housing

X, y = fetch_california_housing(return_X_y=True)
model = LinearRegression()
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores = cross_val_score(model, X, y, cv=kf, scoring='neg_mean_squared_error')

rmse_scores = (-scores) ** 0.5
print(f"Cross Validation RMSE Scores: {rmse_scores}")
print(f"Mean RMSE: {rmse_scores.mean():.3f} ± {rmse_scores.std():.3f}")

Best Practices und Fallstricke

  • Datenlecks vermeiden: Feature-Engineering und Vorverarbeitung müssen innerhalb jedes Trainingsfolds geschehen, nicht vor der CV-Aufteilung. Pipelines sind hier hilfreich.
  • Shuffle: Für zufällige Verteilung der Daten ist shuffle=True sinnvoll, besonders bei zeitlich sortierten Daten jedoch mit Vorsicht einsetzen.
  • K-Fold Anzahl: Üblich sind 5 oder 10 Folds. Mehr Folds erhöhen den Rechenaufwand.

Hyperparameter optimieren

Im Machine Learning sind Hyperparameter jene Einstellungen, die das Lernverhalten eines Modells steuern, aber nicht direkt aus den Trainingsdaten gelernt werden. Beispiele sind die Anzahl der Bäume in einem Random Forest, die Lernrate eines Gradientenboosters oder die Regularisierungsstärke bei linearen Modellen. Die Optimierung dieser Hyperparameter ist entscheidend, um die Modellleistung zu maximieren.

Im Gegensatz zu den Parametern eines Modells (z.B. Gewichte in einem neuronalen Netz), die während des Trainings angepasst werden, müssen Hyperparameter vor dem Training festgelegt werden. Das manuelle Testen verschiedener Kombinationen ist ineffizient und fehleranfällig – hier setzt die systematische Suche an.

Grid Search: Systematische Hyperparameter-Suche

Die wohl bekannteste Methode ist die Grid Search. Dabei definiert man einen Suchraum als diskretes Gitter von Hyperparameterwerten. Das Verfahren trainiert für jede Kombination ein Modell und evaluiert es anhand einer Metrik, meist mittels Cross-Validation. Das Resultat ist die Kombination mit der besten Performance.

In Python mit scikit-learn ist die Anwendung unkompliziert:

from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_iris
from sklearn.metrics import accuracy_score

X, y = load_iris(return_X_y=True)

param_grid: dict[str, list[int | float]] = {
    'n_estimators': [50, 100, 200],
    'max_depth': [None, 10, 20],
    'min_samples_split': [2, 5]
}

model = RandomForestClassifier(random_state=42)
grid_search = GridSearchCV(model, param_grid, cv=5, scoring='accuracy', n_jobs=-1)
grid_search.fit(X, y)

print(f"Beste Parameter: {grid_search.best_params_}")
print(f"Beste Cross-Validation-Accuracy: {grid_search.best_score_:.3f}")

Hinweis: n_jobs=-1 nutzt alle verfügbaren CPU-Kerne, was in Python dank der nativen Multiprozess-Unterstützung effizient ist.

Randomized Search: Effizientere Alternative

Grid Search skaliert schlecht mit der Anzahl der Hyperparameter und deren Werte. Randomized Search wählt stattdessen zufällig eine feste Anzahl von Kombinationen aus dem Suchraum aus. Dies ist oft effizienter und führt zu ähnlich guten Ergebnissen.

from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint

param_dist = {
    'n_estimators': randint(50, 200),
    'max_depth': [None, 10, 20, 30],
    'min_samples_split': randint(2, 10)
}

random_search = RandomizedSearchCV(model, param_dist, n_iter=20, cv=5, scoring='accuracy', n_jobs=-1, random_state=42)
random_search.fit(X, y)

print(f"Beste Parameter: {random_search.best_params_}")
print(f"Beste Cross-Validation-Accuracy: {random_search.best_score_:.3f}")

Best Practices

  • Cross-Validation verwenden: Vermeidet Overfitting auf Trainingsdaten und liefert belastbare Schätzungen.
  • Suchraum sinnvoll einschränken: Ein zu großer Suchraum erhöht Laufzeit und Risiko, in unbrauchbaren Bereichen zu suchen.
  • Parallelisierung nutzen: scikit-learn unterstützt Multiprozess-Parallelität, was bei großen Daten und Modellen entscheidend ist.
  • Pipeline integrieren: Hyperparameter können auch Vorverarbeitungsschritte betreffen. Durch Pipelines lassen sich diese gemeinsam optimieren.
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

pipeline = Pipeline([
    ('scaler', StandardScaler()),
    ('svc', SVC())
])

param_grid = {
    'svc__C': [0.1, 1, 10],
    'svc__kernel': ['linear', 'rbf'],
    'svc__gamma': ['scale', 'auto']
}

grid_search = GridSearchCV(pipeline, param_grid, cv=5, n_jobs=-1)
grid_search.fit(X, y)

print(f"Beste Parameter: {grid_search.best_params_}")

Hier wird die Skalierung als Teil der Pipeline betrachtet und deren Parameter können ebenfalls optimiert werden. Dies entspricht dem Python-Idioms "composition over inheritance" und fördert reproduzierbare, wartbare ML-Workflows.

Zusammenfassung

Hyperparameter-Optimierung ist ein zentraler Schritt, um Modelle an reale Daten anzupassen. Python und scikit-learn bieten mit Grid Search und Randomized Search bewährte, einfach nutzbare Werkzeuge, die durch Parallelisierung und Pipeline-Integration den Workflow deutlich vereinfachen.