Scikit-Learn Pipelines 2026: Feature Engineering und Interview-Fragen

Scikit-learn Pipelines mit ColumnTransformer für Feature Engineering meistern. Preprocessing-Best-Practices und Vorbereitung auf ML-Interviews.

Scikit-Learn Pipelines 2026: Feature Engineering und Interview-Fragen

Scikit-learn Pipelines transformieren unstrukturierten Preprocessing-Code in reproduzierbare, produktionsreife Workflows. Mit Version 1.9, die im Juni 2026 veröffentlicht wurde, bleiben Pipeline und ColumnTransformer das Fundament jedes ernsthaften Machine-Learning-Projekts – jetzt mit Callback-Monitoring, verbesserter HTML-Visualisierung und Array-API-Unterstützung.

Interview-Tipp

Interviewer fragen oft: "Wie verhindern Sie Data Leakage während der Cross-Validation?" Die Antwort lautet: Pipelines. Das Fitten der Preprocessing-Schritte innerhalb der CV-Schleife stellt sicher, dass Testdaten niemals Skalierungs- oder Encoding-Entscheidungen beeinflussen.

Warum Pipelines Data Leakage eliminieren

Data Leakage tritt auf, wenn Informationen aus dem Testset das Preprocessing beeinflussen. Ein häufiger Fehler: Den StandardScaler auf dem gesamten Datensatz fitten, bevor man splittet. Der Scaler lernt Mittelwert und Varianz aus Testsamples, was die Cross-Validation-Scores künstlich erhöht.

Pipelines beheben dies, indem sie Transformer und Estimatoren zu einem einzigen Objekt verketten, das alle Schritte gemeinsam fittet:

python
# pipeline_basics.py
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score

# Create a pipeline that scales features and trains a classifier
pipeline = Pipeline([
    ('scaler', StandardScaler()),  # Step 1: Normalize features
    ('classifier', LogisticRegression(max_iter=1000))  # Step 2: Train model
])

# cross_val_score fits the scaler separately for each fold
# No data leakage: test fold is never seen during scaler.fit()
scores = cross_val_score(pipeline, X, y, cv=5, scoring='accuracy')
print(f"Mean accuracy: {scores.mean():.3f} (+/- {scores.std():.3f})")

Das Pipeline-Objekt implementiert fit, predict und score, wodurch es mit jedem Scikit-learn-Estimator austauschbar ist. Das bedeutet, GridSearchCV, RandomizedSearchCV und alle Cross-Validation-Utilities funktionieren ohne Modifikation.

ColumnTransformer für gemischte Datentypen

Reale Datensätze enthalten numerische Spalten (Alter, Gehalt) und kategorische Spalten (Land, Produkttyp). ColumnTransformer wendet unterschiedliches Preprocessing auf verschiedene Spaltensubsets an und konkateniert dann die Ergebnisse:

python
# column_transformer_example.py
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
import pandas as pd

# Sample dataset with mixed types
df = pd.DataFrame({
    'age': [25, 30, None, 45],
    'salary': [50000, 60000, 75000, None],
    'country': ['US', 'UK', 'DE', 'US'],
    'education': ['Bachelor', 'Master', 'PhD', 'Bachelor']
})

# Define numeric preprocessing: impute missing values, then scale
numeric_transformer = Pipeline([
    ('imputer', SimpleImputer(strategy='median')),
    ('scaler', StandardScaler())
])

# Define categorical preprocessing: impute with mode, then one-hot encode
categorical_transformer = Pipeline([
    ('imputer', SimpleImputer(strategy='most_frequent')),
    ('encoder', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
])

# Combine transformers with ColumnTransformer
preprocessor = ColumnTransformer(
    transformers=[
        ('num', numeric_transformer, ['age', 'salary']),
        ('cat', categorical_transformer, ['country', 'education'])
    ],
    verbose_feature_names_out=True  # Prefix output names with transformer name
)

# Fit and inspect output shape
X_transformed = preprocessor.fit_transform(df)
print(f"Transformed shape: {X_transformed.shape}")
print(f"Feature names: {preprocessor.get_feature_names_out()}")

Der Parameter verbose_feature_names_out (in Version 1.6 erweitert, um Strings und Callables zu akzeptieren) steuert die Benennung der Output-Features. Die Einstellung auf True präfixiert jedes Feature mit dem Transformer-Namen und verhindert so Namenskollisionen, wenn mehrere Transformer ähnliche Spaltennamen generieren.

Automatische Spaltenauswahl mit make_column_selector

Hartcodierte Spaltennamen brechen, wenn sich Datensätze ändern. make_column_selector wählt Spalten automatisch nach dtype aus:

python
# automatic_column_selection.py
from sklearn.compose import ColumnTransformer, make_column_selector
from sklearn.preprocessing import StandardScaler, OneHotEncoder

# Select columns by dtype: no hardcoded column names
preprocessor = ColumnTransformer(
    transformers=[
        ('num', StandardScaler(), make_column_selector(dtype_include='number')),
        ('cat', OneHotEncoder(handle_unknown='ignore'),
         make_column_selector(dtype_include='object'))
    ],
    remainder='passthrough'  # Keep unprocessed columns as-is
)

# Works with any DataFrame that has numeric and object columns
X_processed = preprocessor.fit_transform(df)

Der Parameter remainder steuert, was mit Spalten passiert, die von keinem Transformer erfasst werden. Optionen sind 'drop' (Standard), 'passthrough' (unverändert behalten) oder ein Transformer, der auf die verbleibenden Spalten angewendet wird.

Bereit für deine Data Science & ML-Interviews?

Übe mit unseren interaktiven Simulatoren, Flashcards und technischen Tests.

Feature Engineering innerhalb von Pipelines

Pipelines gehen über Preprocessing hinaus und umfassen Feature-Engineering-Schritte. Benutzerdefinierte Transformer erben von BaseEstimator und TransformerMixin:

python
# custom_transformer.py
from sklearn.base import BaseEstimator, TransformerMixin
import numpy as np

class DateFeatureExtractor(BaseEstimator, TransformerMixin):
    """Extract year, month, day, and weekday from datetime columns."""
    
    def __init__(self, date_column='date'):
        self.date_column = date_column
    
    def fit(self, X, y=None):
        # No fitting required for date extraction
        return self
    
    def transform(self, X):
        X = X.copy()
        dates = pd.to_datetime(X[self.date_column])
        
        # Extract temporal features
        X['year'] = dates.dt.year
        X['month'] = dates.dt.month
        X['day'] = dates.dt.day
        X['weekday'] = dates.dt.weekday
        X['is_weekend'] = (dates.dt.weekday >= 5).astype(int)
        
        # Drop original date column
        return X.drop(columns=[self.date_column])
    
    def get_feature_names_out(self, input_features=None):
        # Required for Pipeline.get_feature_names_out() to work
        return ['year', 'month', 'day', 'weekday', 'is_weekend']

# Integrate into a full pipeline
full_pipeline = Pipeline([
    ('date_features', DateFeatureExtractor(date_column='signup_date')),
    ('preprocessor', preprocessor),
    ('model', LogisticRegression())
])

Die Implementierung von get_feature_names_out ermöglicht es der neuen HTML-Darstellung in Scikit-learn 1.9, Output-Feature-Namen anzuzeigen, was Debugging und Dokumentation erleichtert.

Hyperparameter-Tuning über Pipeline-Schritte hinweg

GridSearchCV stimmt Parameter über alle Pipeline-Schritte mit der step__parameter-Namenskonvention ab:

python
# pipeline_gridsearch.py
from sklearn.model_selection import GridSearchCV
from sklearn.ensemble import RandomForestClassifier

# Build pipeline with tunable components
pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('classifier', RandomForestClassifier(random_state=42))
])

# Define parameter grid: note the double underscore syntax
param_grid = {
    'preprocessor__num__imputer__strategy': ['mean', 'median'],
    'classifier__n_estimators': [100, 200],
    'classifier__max_depth': [10, 20, None]
}

# GridSearchCV handles all combinations automatically
grid_search = GridSearchCV(
    pipeline,
    param_grid,
    cv=5,
    scoring='f1_weighted',
    n_jobs=-1
)

grid_search.fit(X_train, y_train)
print(f"Best params: {grid_search.best_params_}")
print(f"Best score: {grid_search.best_score_:.3f}")

Der doppelte Unterstrich (__) greift auf verschachtelte Parameter zu. Für ColumnTransformer enthält der Pfad den Transformer-Namen: preprocessor__num__imputer__strategy erreicht den strategy-Parameter des Imputers innerhalb des numerischen Transformers.

Transformer-Caching mit dem memory-Parameter

Komplexes Preprocessing auf großen Datensätzen kann langsam sein. Der Parameter memory cached gefittete Transformer auf der Festplatte:

python
# cached_pipeline.py
from sklearn.pipeline import Pipeline
from tempfile import mkdtemp
import joblib

# Create a cache directory
cachedir = mkdtemp()

# Pipeline caches intermediate steps
cached_pipeline = Pipeline(
    [
        ('preprocessor', preprocessor),  # Cached after first fit
        ('classifier', RandomForestClassifier())
    ],
    memory=cachedir  # Or use joblib.Memory for more control
)

# First fit: slow (computes all transformations)
cached_pipeline.fit(X_train, y_train)

# Second fit with same X_train: fast (loads cached transformers)
cached_pipeline.fit(X_train, y_train)  # Skips preprocessor fitting

Caching ist besonders nützlich während der Hyperparameter-Suche, bei der das gleiche Preprocessing auf mehrere Modellkonfigurationen angewendet wird. Der finale Estimator (Classifier oder Regressor) wird niemals gecached, nur Zwischen-Transformer.

Training-Monitoring mit Callbacks (scikit-learn 1.9)

Die Callback-API in Version 1.9 fügt Progress-Monitoring zu Pipelines hinzu:

python
# callback_monitoring.py
from sklearn.callback import ProgressBar, ScoringMonitor
from sklearn.linear_model import LogisticRegression

# Display progress during GridSearchCV
with ProgressBar():
    grid_search = GridSearchCV(
        pipeline,
        param_grid,
        cv=5,
        n_jobs=1  # Progress bars require single-threaded execution
    )
    grid_search.fit(X_train, y_train)

# Monitor scoring metrics per iteration
with ScoringMonitor(X_val, y_val, scoring='accuracy') as monitor:
    logreg = LogisticRegression(solver='lbfgs', max_iter=500)
    logreg.fit(X_train, y_train)
    print(f"Scores per iteration: {monitor.scores_}")

Callbacks funktionieren mit Pipeline, StandardScaler, LogisticRegression (LBFGS-Solver) und allen Search-CV-Klassen. Diese experimentelle Funktion bietet Einblick in lang laufende Fits ohne benutzerdefinierten Logging-Code.

FeatureUnion für parallele Feature-Extraktion

FeatureUnion führt mehrere Transformer parallel aus und konkateniert ihre Ausgabe horizontal:

python
# feature_union_example.py
from sklearn.pipeline import FeatureUnion, Pipeline
from sklearn.decomposition import PCA
from sklearn.feature_selection import SelectKBest, f_classif

# Combine PCA and univariate selection
feature_union = FeatureUnion([
    ('pca', PCA(n_components=5)),
    ('select', SelectKBest(f_classif, k=10))
])

# Pipeline: preprocess, combine features, classify
pipeline = Pipeline([
    ('preprocessor', preprocessor),
    ('features', feature_union),
    ('classifier', LogisticRegression())
])

# Output contains 5 PCA components + 10 selected features = 15 features
pipeline.fit(X_train, y_train)

Version 1.7.2 fügte eine Validierung hinzu, die sicherstellt, dass alle Transformer 2D-Ausgaben zurückgeben. Dies erkennt Fehler frühzeitig, wenn ein benutzerdefinierter Transformer versehentlich ein 1D-Array zurückgibt.

Serialisierung und Deployment

Pipelines werden mit joblib serialisiert und bewahren alle gefitteten Parameter:

python
# model_deployment.py
import joblib

# Save the entire pipeline (preprocessing + model)
joblib.dump(pipeline, 'churn_predictor.pkl')

# Load in production
loaded_pipeline = joblib.load('churn_predictor.pkl')

# Predict on new data (same preprocessing automatically applied)
new_data = pd.DataFrame({'age': [32], 'salary': [65000], ...})
predictions = loaded_pipeline.predict(new_data)

Die serialisierte Datei enthält alles: Spaltenauswahl-Logik, gefittete Scaler-Mittelwerte und Varianzen, Encoder-Kategorien und Modellgewichte. Das Deployment erfordert nur Scikit-learn und joblib, keinen benutzerdefinierten Preprocessing-Code.

Versionskompatibilität

Pipelines, die mit Scikit-learn 1.8 serialisiert wurden, laden möglicherweise nicht korrekt auf 1.9, wenn sie veraltete Parameter verwenden. Die Scikit-learn-Version sollte in der Produktion immer fixiert und Upgrades vor dem Deployment getestet werden.

Interview-Fragen zu Scikit-Learn Pipelines

F: Was ist Data Leakage und wie verhindern Pipelines es?

Data Leakage tritt auf, wenn Informationen aus dem Validierungs- oder Testset das Modelltraining beeinflussen. Das klassische Beispiel: Einen StandardScaler auf dem gesamten Datensatz fitten, bevor man splittet. Der Mittelwert und die Standardabweichung des Scalers enthalten Testsamples, was Cross-Validation-Scores künstlich erhöht.

Pipelines verhindern dies, indem sie das Preprocessing innerhalb der Cross-Validation-Schleife kapseln. Wenn cross_val_score pipeline.fit() aufruft, fittet jeder Fold den Scaler nur auf Trainingsdaten. Testfold-Statistiken lecken niemals in das Preprocessing.

F: Wie greift man auf Parameter verschachtelter Pipeline-Schritte zu und modifiziert sie?

Die Doppel-Unterstrich-Syntax wird verwendet: pipeline.set_params(classifier__n_estimators=200). Für ColumnTransformer wird der Transformer-Name eingeschlossen: pipeline.set_params(preprocessor__num__scaler__with_mean=False). Die Methode get_params() gibt alle verschachtelten Parameter als flaches Dictionary zurück, nützlich für Inspektion und Logging.

F: Wann sollte FeatureUnion vs ColumnTransformer verwendet werden?

ColumnTransformer wendet verschiedene Transformer auf verschiedene Spalten derselben Eingabe an. FeatureUnion wendet verschiedene Transformer auf die gesamte Eingabe an und konkateniert horizontal. ColumnTransformer wird für heterogenes Spalten-Preprocessing verwendet (numerisch vs. kategorisch). FeatureUnion wird für Feature-Augmentierung verwendet, bei der mehrere Extraktionsmethoden (PCA, polynomiale Features, domänenspezifische Extraktoren) komplementäre Features aus denselben Daten erzeugen.

F: Wie debuggt man eine fehlschlagende Pipeline?

verbose=True auf der Pipeline setzen, um Schritt-Timings zu sehen. Auf Zwischenergebnisse mit pipeline.named_steps['step_name'].transform(X) für eine gefittete Pipeline zugreifen. In Scikit-learn 1.9 zeigt die HTML-Darstellung gefittete Attribute und Output-Feature-Namen an, was das Debugging in Jupyter Notebooks vereinfacht. Für tiefere Inspektion pipeline[:-1].fit_transform(X, y) verwenden, um die Ausgabe direkt vor dem finalen Estimator zu erhalten.

Produktions-Checkliste für ML-Pipelines

  • Scikit-learn-Version in den Requirements fixieren, um Serialisierungsprobleme zu vermeiden
  • make_column_selector anstelle hartcodierter Spaltennamen verwenden, wenn sich Datensätze ändern können
  • handle_unknown='ignore' auf OneHotEncoder setzen, um neue Kategorien in der Produktion zu handhaben
  • Teures Preprocessing während der Entwicklung mit dem memory-Parameter cachen
  • Pipeline-Output-Shape und Feature-Namen in Tests vor dem Deployment validieren
  • get_feature_names_out() zusammen mit dem Modell für Feature-Importance-Analyse speichern
  • Pipeline innerhalb von GridSearchCV verwenden, niemals umgekehrt, um korrektes CV-Verhalten sicherzustellen

Fang an zu üben!

Teste dein Wissen mit unseren Interview-Simulatoren und technischen Tests.

Tägliche Challenge

Findest du den Bug in Data Science & ML?

Ein echter Codeausschnitt, ein versteckter Bug, ein Versuch pro Tag. Zum Ausprobieren ohne Konto.

Anthony Fillion-Maillet

Geschrieben von

Anthony Fillion-Maillet

Gründer von SharpSkill

Seit über 10 Jahren Fullstack-Entwickler. Er leitet SharpSkill und verantwortet alles, was hier erscheint.

Aktualisiert am 2. September 2026

Teilen

Verwandte Artikel