Machine Learning mit Python – Von Daten zu Modellen
Python und AI, Teil 2
Der Weg von den Rohdaten bis zum fertigen ML-Modell folgt einer strukturierten Abfolge technischer Schritte. Ziel ist es, aus unstrukturierten, oft heterogenen Datenquellen belastbare Modelle zu entwickeln, die verlässliche Vorhersagen treffen können. Dabei durchläuft jedes Projekt typische Phasen – von der Datensammlung über die Aufbereitung und Modellierung bis hin zur Evaluierung und Bereitstellung. Diese Pipeline ist unabhängig vom Datentyp (Tabellen, Text, Bild oder Audio) und stellt den Standardprozess in Data-Science- und KI-Projekten dar (Bild 1). Sie bildet die methodische Grundlage moderner, datengetriebener Entwicklung.
Von den Daten zum Modell
Es ergeben sich die folgenden Schritte:
- Datenakquise und Integration: Zunächst werden relevante Rohdaten aus allen verfügbaren Quellen (Datenbanken, Dateien, APIs, Sensorsysteme und andere) gesammelt und vereinigt. Oft ist dies ein ETL-Prozess: Daten werden extrahiert, bereinigt und in ein einheitliches Format gebracht. Dazu gehört das Aufspüren fehlender oder inkonsistenter Datensätze.
- Explorative Datenanalyse (EDA) und Vorverarbeitung: In der EDA untersucht man Datenverteilungen, Zusammenhänge und Anomalien (zum Beispiel mit Visualisierungen). Anschließend folgt die Datenvorbereitung: fehlende Werte füllen, Ausreißer behandeln und Merkmale codieren (One-Hot, Label-Encoding et cetera). Für numerische Features wird meist normalisiert oder skaliert. Beim Feature Engineering werden aus Rohdaten aussagekräftige Merkmale abgeleitet (zum Beispiel durch Aggregationen, Transformationen oder Domänenwissen). Abhängig vom Datentyp kommen unterschiedliche Methoden zum Einsatz (Tabellen: kategoriale Codierung, Texte: Tokenisierung/Embeddings, Bilder: Normalisierung/Augmentierung).
- Datenaufteilung: Der Datensatz wird in Trainings- und Testdaten aufgeteilt, um später Generalisierbarkeit zu prüfen. Typischerweise verwendet man zum Beispiel train_test_split in scikit-learn. So kann man beim Training über Splits die Modellperformance abschätzen und Überanpassung vermeiden.
- Modellwahl: Je nach Aufgabenstellung (Regression, Klassifikation, Clustering et cetera) wählt man geeignete Modellklassen und Algorithmen aus. Klassische Methoden sind etwa lineare Modelle, Entscheidungsbäume oder k-nächste Nachbarn; bei großen Daten oft neuronale Netze. Die Wahl berücksichtigt Eigenschaften der Daten (Größe, Dimensionalität, Ausreißer, Nichtlinearitäten) und Anforderungen (Interpretierbarkeit, Ressourcen).
- Training und Hyperparameter-Tuning: Die gewählten Modelle werden am Trainingssatz gelernt. Dabei werden unterschiedliche Modelle experimentell angepasst und deren Hyperparameter optimiert (zum Beispiel mittels Grid Search oder Random Search). Das Ziel ist, die Modellleistung (Fehlerreduktion) zu maximieren. Oft wird dazu automatisiert der Suchraum durchforstet, um etwa Lernrate, Regularisierung oder Netzgröße zu bestimmen.
- Evaluierung: Nach dem Training bewertet man das Modell mit dem unabhängigen Testdatensatz. Es werden Kennzahlen wie Genauigkeit oder Präzision berechnet, um die Vorhersagequalität zu quantifizieren. Zusätzlich kann man Kreuzvalidierung nutzen, um die Stabilität der Ergebnisse zu erhöhen. Basierend auf den Metriken entscheidet man, ob das Modell die gewünschten Ziele erreicht und eventuell weitere Optimierungsrunden nötig sind.
- Modell-Export und Inferenz: Abschließend wird das fertige Modell gespeichert (zum Beispiel als Datei, Container-Image oder Modellartefakt) und in die Zielumgebung überführt. In der Produktion stellt man es typischerweise als Dienst (REST-API), Batch-Job oder eingebettetes Modell bereit, damit es neue Daten klassifizieren beziehungsweise vorhersagen kann.
Dieser Workflow ist für strukturierte (Tabellen) wie für unstrukturierte Daten (Texte, Bilder, Audio) ähnlich, wenngleich die konkreten Vorverarbeitungs- und Feature-Engineering-Schritte je nach Datentyp variieren.
Datenvorverarbeitung und Modelltraining mit Python
Wir demonstrieren den Workflow von der Datenerfassung bis zur Modellauslieferung anhand eines einfachen Klassifikationsbeispiels (Iris-Datensatz). Die zugehörigen Python-Skripte kann man beispielsweise in einem Jupyter-Notebook laden. Die Datei für dieses Beispiel findet Sie auf der Website des Autors.
Datenakquise und Integration
Im Beispiel laden wir den Iris-Datensatz von scikit-learn, der bereits in einem geeigneten Format vorliegt. Anschließend vereinigen wir alle Merkmale in einem DataFrame. Dabei wäre es wichtig, Inkonsistenzen oder fehlende Werte zu erkennen und sie zu bereinigen:
from sklearn.datasets import load_iris import pandas as pd # Daten laden (hier Iris-Datensatz) und in DataFrame umwandeln iris = load_iris() df = pd.DataFrame(iris.data, columns=iris.feature_names) df['target'] = iris.target # Zielvariable (0,1,2 = Arten) print(df.head())
Das führt zu folgender Ausgabe:
| sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) \
| target |
| 0 | 5,1 | 3,5 | 1,4 | 0,2 | 0 |
| 1 | 4,9 | 3,0 | 1,4 | 0,2 | 0 |
| 2 | 4,7 | 3,2 | 1,3 | 0,2 | 0 |
| 3 | 4,6 | 3,1 | 1,6 | 0,2 | 0 |
| 4 | 5,0 | 3,6 | 1,4 | 0,2 | 0 |
Erläuterung:
- from sklearn.datasets import load_iris importiert die Funktion zum Laden des Datensatzes,
- iris = load_iris() lädt die Daten in ein Python-Objekt,
- pd.DataFrame(iris.data, columns=iris.feature_names) erstellt daraus eine tabellarische Struktur mit Spalten wie sepal length (cm), sepal width (cm) und so fort.
- df['target'] = iris.target fügt eine zusätzliche Spalte hinzu, die die Zielvariable (die Art der Iris-Blume) enthält. Die Werte 0, 1 und 2 stehen dabei für die drei Klassen.
- print(df.head()) zeigt die ersten fünf Zeilen der Tabelle an, um zu prüfen, ob die Daten korrekt geladen wurden.
Explorative Datenanalyse (EDA) und Vorverarbeitung
Im nächsten Schritt untersuchen wir die Daten: Verteilungen, Zusammenhänge und mögliche Ausreißer. Klassische EDA-Methoden sind Histogramme, Boxplots oder Korrelationsmatrizen, um Verteilungen und Ausreißer visuell zu identifizieren. Anschließend werden fehlende Werte und Ausreißer behandelt sowie die Daten normalisiert/standardisiert und kategorische Merkmale codiert. Beim Iris-Datensatz gibt es keine fehlenden Werte, und alle Features sind numerisch. Wir demonstrieren daher die Standardisierung („Z-Score-Normalisierung“), die viele Lernalgorithmen robuster und schneller konvergieren lässt:
from sklearn.preprocessing import StandardScaler # Numerische Merkmale standardisieren (Mittelwert=0, Varianz=1) features = df.drop(columns=['target']) scaler = StandardScaler() X_scaled = scaler.fit_transform(features)
Datenaufteilung
Bevor wir ein Modell trainieren, teilen wir den Datensatz in Trainings- und Testdaten auf. Dies ist wichtig, um die Generalisierbarkeit des Modells zu prüfen und Überanpassung zu vermeiden. Typischerweise nutzt man Funktionen wie train_test_split aus scikit-learn, um die Daten zufällig zu splitten. Im Beispiel verwenden wir 30 Prozent der Daten als Testset:
from sklearn.model_selection import train_test_split # Aufteilen in Trainings- und Testdaten X_train, X_test, y_train, y_test = train_test_split( X_scaled, df['target'], test_size=0.3, random_state=42, shuffle=True )
Modellwahl
Für ein Klassifikationsproblem wie den Iris-Datensatz wählt man ein geeignetes Modell. Beliebte Optionen sind etwa logistische Regression, Entscheidungsbäume/Random Forests oder Support-Vektor-Maschine (SVM). Die Wahl hängt von Eigenschaften wie Datengröße, Dimensionalität und Interpretierbarkeit ab. Hier verwenden wir einen RandomForestClassifier, der oft gute Leistung liefert und unempfindlich gegenüber Ausreißern ist. Für einfachere Modelle könnte man auch eine logistische Regression einsetzen.
from sklearn.ensemble import RandomForestClassifier # Modell erstellen (hier: Random Forest) model = RandomForestClassifier(random_state=42)
Training und Hyperparameter-Tuning
Das gewählte Modell wird nun auf dem Trainingssatz trainiert. Gleichzeitig optimieren wir die Hyperparameter, um die Leistung zu maximieren. In scikit-learn kann man hierzu GridSearchCV (Grid-Suche) oder RandomizedSearchCV verwenden Dabei werden verschiedene Parameterkombinationen ausprobiert und mittels Kreuzvalidierung evaluiert. Im Beispiel optimieren wir etwa die Anzahl der Bäume und die maximale Tiefe des Waldes:
from sklearn.model_selection import GridSearchCV
param_grid = {
'n_estimators': [10, 50, 100],
'max_depth': [None, 2, 4]
}
grid = GridSearchCV(
RandomForestClassifier(random_state=42),
param_grid, cv=5
)
grid.fit(X_train, y_train)
print("Beste Parameter:", grid.best_params_)
Evaluierung
Nach dem Training bewerten wir das finale Modell auf dem unabhängigen Testsatz. Typische Kennzahlen sind Genauigkeit (Accuracy), Präzision, Recall (Sensitivität) und der F1-Score, insbesondere bei unbalancierten Daten. Außerdem kann man ROC-AUC (Receiver Operating Curve) für binäre Probleme berechnen. Das folgende Beispiel gibt die Konfusionsmatrix und den Klassifikationsreport aus:
from sklearn.metrics import classification_report, confusion_matrix
y_pred = grid.predict(X_test)
print("Confusion Matrix:\n", confusion_matrix(y_test, y_pred))
print("\nClassification Report:\n", classification_report(y_test, y_pred))
Die Ausgabe könnte für das Beispiel etwa (Zufall) so aussehen:
Confusion Matrix: [[16 0 0] [ 0 19 2] [ 0 1 12]] Classification Report:
| precision | recall | f1-score | Support |
| 0 | 1.00 | 1.00 | 1.00 | 16 |
| 1 | 0.95 | 0.90 | 0.92 | 21 |
| 2 | 0.86 | 0.92 | 0.89 | 13 |
| accuracy |
|
| 0.94 | 50 |
| macro avg | 0.94 | 0.94 | 0.94 | 50 |
| weighted avg | 0.95 | 0.94 | 0.94 | 50 |
Was bedeuten diese Werte? Die Matrix zeigt, wie viele Beispiele jeder tatsächlichen Klasse korrekt oder falsch klassifiziert wurden:
- Erste Zeile (Klasse 0): 16-mal korrekt erkannt, keine Fehlklassifikation.
- Zweite Zeile (Klasse 1): 19-mal korrekt erkannt, 2 fälschlich als Klasse 2 klassifiziert.
- Dritte Zeile (Klasse 2): 12-mal korrekt erkannt, 1-mal mit Klasse 1 verwechselt.
Das Modell unterscheidet die Klassen sehr zuverlässig; nur wenige Verwechslungen treten zwischen Klasse 1 und 2 auf. Zu den Metriken können die in Tabelle 1 zusammengefassten Aussagen getroffen werden.
Tabelle 1: Charakterisierung der Metriken
| Metrik | Bedeutung | Interpretation |
| Precision (Genauigkeit) | Anteil der richtig vorhergesagten positiven Fälle an allen vom Modell als positiv eingestuften Fällen. –> Sie misst, wie zuverlässig das Modell bei positiven Vorhersagen ist. | Für Klasse 0 beträgt sie 1.00 –> keine Fehlklassifikationen. Für Klasse 2 liegt sie bei 0.86 –> einige falsch-positive Zuordnungen. |
| Recall (Trefferquote) | Anteil der richtig erkannten positiven Fälle an allen tatsächlich vorhandenen positiven Fällen. –> Sie misst, wie vollständig das Modell die tatsächlichen Positiven erfasst. | Klasse 1 hat 0.90 –> das Modell übersieht etwa 10 Prozent dieser Fälle. |
| F1-Score | Harmonisches Mittel aus Precision und Recall. | Werte um 0.9 bis 1.0 zeigen eine sehr gute Gesamtleistung. |
| Support | Anzahl der Beispiele je Klasse im Testdatensatz. | Zeigt, dass das Testset leicht unbalanciert ist (zum Beispiel 21 versus 13 Beispiele). |
Die Gesamtbewertungen:
- Accuracy = 0.94 –> 94 % der Testbeispiele wurden korrekt klassifiziert.
- Macro Avg (arithmetischer Mittelwert über alle Klassen) ≈ 0.94 –> zeigt, dass die Klassen gleichmäßig gut erkannt werden.
- Weighted Avg (gewichteter Mittelwert nach Klassenhäufigkeit) ≈ 0.94 –> kein nennenswerter Bias zugunsten häufiger Klassen.
Modell-Export und Inferenz
Abschließend speichern wir das trainierte Modell und stellen es bereit. In einer Produktivumgebung wird das Modell oft als Dienst (zum Beispiel über ein REST-API) bereitgestellt, sodass es neue Daten vorhersagen kann.