# 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. - Published: 2026-09-02 - Updated: 2026-09-02 - Author: Anthony Fillion-Maillet - Reading time: 5 min --- Scikit-learn Pipelines transformieren unstrukturierten Preprocessing-Code in reproduzierbare, produktionsreife Workflows. Mit [Version 1.9](https://scikit-learn.org/stable/whats_new/v1.9.html), 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. ## 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](https://scikit-learn.org/stable/whats_new/v1.9.html) 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 --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/de/blog/data-science/scikit-learn-pipelines-feature-engineering-interview-2026