Januar 12, 2026

Effiziente Machine Learning Pipelines mit Scikit-Learn

In den meisten Machine-Learning-Projekt kommt irgendwann der Moment, an dem die Datenaufbereitung unübersichtlich wird: Man hat mehrere Schritte zur Vorverarbeitung, unterschiedliche Feature-Typen und Modelle, die verschiedene Input-Formate erwarten. Spätestens dann lohnt es sich auf Pipelines zurückzugreifen um einem einen strukturierten Ansatz zu folgen. Sie haben den Vorteil, dass sie weniger fehleranfällig sind und reproduzierbar sind. Insbesondere wenn es darum geht Trainings- und Testdaten sauber zu trennen und trotzdem konsistent aufzubereiten. Zudem sind sie deutlich besser wartbar und helfen dadurch beispielsweise beim Retraining von Modellen in den Verarbeitungsschritte konsistent zu bleiben

Scikit-Learn Pipelines

Eine Pipeline in Scikit-Learn ist ein Objekt, das eine Abfolge von Transformationen und einem abschließenden Modell bündelt. Alle Schritte sind dabei vollständig kompatibel mit Scikit-Learn’s API – inklusive GridSearchCV, Cross-Validation und Model Export.

Beispiel:

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

pipe = Pipeline([
    ('imputer', SimpleImputer(strategy='mean')),
    ('scaler', StandardScaler()),
    ('model', LogisticRegression())
])

Wichtige Regeln

  • Alle Schritte außer dem letzten müssen Transformer sein
  • Der letzte Schritt ist das Modell
  • fit() wird von links nach rechts ausgeführt
  • predict() nutzt exakt dieselbe Transformationskette

Beispieldatensatz

Um die Funktionsweise von Pipelines besser zu zeigen, verwenden wir im folgenden den Beispieldatensatz „Adult Census Income“. Wir trainieren ein Model, welches vorhersagen soll, ob eine Person mehr als 50.000 USD pro Jahr verdient.

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
import pandas as pd

adult = fetch_openml(
    name="adult",
    version=2,
    as_frame=True
)

X = adult.data
y = adult.target

# Train-Test Split
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y
)

Feature Engineering mit ColumnTransformer

In realen Datensätzen hast du fast immer heterogene Feature-Typen:

  • numerische Features
  • kategoriale Features
  • weitere Datentypen wie Datum, Text, etc.

ColumnTransformer hilft hier bei der konsistenten und übersichtlichen Verarbeitung.

from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler

numeric_features = [
    'age',
    'hours-per-week',
    'capital-gain',
    'capital-loss'
]

categorical_features = [
    'workclass',
    'education',
    'marital-status',
    'occupation',
    'relationship',
    'race',
    'sex',
    'native-country'
]

# Numerische  Pipeline
numeric_transformer = Pipeline([
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())
])

# Kategoriale 
categorical_transformer = Pipeline([
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('encoder', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
])

# Zusammenführen
preprocessor = ColumnTransformer([
    ('num', numeric_transformer, numeric_features),
    ('cat', categorical_transformer, categorical_features)
])

Eigene Transformer

Wenn Standard-Transformer nicht reichen, kannst man eigene schreiben:

from sklearn.base import BaseEstimator, TransformerMixin

class LogTransformer(BaseEstimator, TransformerMixin):
    def fit(self, X, y=None):
        return self

    def transform(self, X):
        return np.log1p(X)

End-to-End Pipeline

Wenn nun Transformationen und Modell zusammen ausgeführt werden sollen, dann kann man diese in eine Pipeline zusammenführen. Dabei wird das „fitten“ der Pipeline nur auf den Trainingsdaten ausgeführt. Für die Vorhersage wird auf den Testdaten dann „predict()“ verwendet:

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

model_pipeline = Pipeline([
    ('preprocessing', preprocessor),
    ('classifier', LogisticRegression(max_iter=1000, class_weight='balanced'))
])

# Training
model_pipeline.fit(X_train, y_train)

# Vorhersage
y_pred = model_pipeline.predict(X_test)
y_proba = model_pipeline.predict_proba(X_test)

Cross-Validation ohne Dataleaks

Pipelines helfen vor allem auch dabei, Cross-Validation sauber zu implementieren, ohne das Dataleaks entstehen. Jeder Fold bekommt dabei ein eigenes Feature Engineering:

from sklearn.model_selection import cross_val_score

cv_scores = cross_val_score(
    model_pipeline,
    X_train,
    y_train,
    cv=5,
    scoring='roc_auc',
    n_jobs=-1
)

print(f"Mean ROC-AUC: {cv_scores.mean():.3f}")

Hyperparameter-Tuning

Auch das Optimieren von Hyperparametern lässt sich elegant in Pipelines integrieren:

from sklearn.model_selection import GridSearchCV

param_grid = {
    'classifier__C': [0.01, 0.1, 1, 10]
}

grid = GridSearchCV(
    model_pipeline,
    param_grid=param_grid,
    cv=5,
    scoring='roc_auc',
    n_jobs=-1
)

grid.fit(X_train, y_train)

grid.best_params_

best_pipeline = grid.best_estimator_

Retraining-Pipelines

Besonders hilfreich sind Pipelines, wenn es darum geht regelmäßiges Retraining von bestehenden Modellen durchzuführen.

Ein typisches Retraining-Szenario sieht so aus:

  • Neue Daten kommen regelmäßig
  • Feature Engineering bleibt gleich
  • Modell wird auf neuen Daten neu trainiert
  • Das Ergebnis muss reproduzierbar sein

Wenn man bereits eine bestehende Pipeline hat, kann man das so umsetzen:

import joblib

def retrain_model(X_new, y_new, pipeline):
    pipeline.fit(X_new, y_new)
    return pipeline

# Model persistieren
joblib.dump(best_pipeline, "income_classifier_pipeline.joblib")

# Model laden und ausführen
loaded_pipeline = joblib.load("income_classifier_pipeline.joblib")
loaded_pipeline.predict(new_data)

Fazit

Scikit-Learn Pipelines helfen nicht nur beim Aufräumen deines Codes, sondern ermöglichen modulares, nachvollziehbares und robustes Feature Engineering.

  1. Sauberer Code: Klare Trennung der Schritte, keine Redundanz.
  2. Automatische Cross-Validation: Alle Schritte werden in jedem Fold korrekt ausgeführt.
  3. Einfache Hyperparameter-Optimierung: GridSearchCV oder RandomizedSearchCV funktionieren problemlos mit Pipelines.
  4. Produktionsbereit: Die gesamte Pipeline kann via joblib gespeichert und geladen werden.
  5. Weniger Daten-Leaks: Transformationen passieren innerhalb der Trainingsdaten beim Cross-Validation.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert