How do I build a scikit-learn Pipeline and why should I?
Short answer
A Pipeline chains preprocessing steps and a model into one object, so fit and predict apply every step in order. It prevents data leakage during cross-validation and keeps training and prediction consistent.
The short version
A Pipeline chains transformers (like a scaler) and a final estimator (like a classifier) into a single object. Calling fit runs every step in order on the training data, and predict applies the same steps to new data. The big wins are correctness (no leakage during cross-validation) and consistency (the exact same preprocessing is applied at training and at prediction).
Building one
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
model = make_pipeline(
StandardScaler(),
LogisticRegression(),
)
model.fit(X_train, y_train)
model.score(X_test, y_test)
make_pipeline names the steps for you from their types. Use Pipeline([...]) with explicit (name, step) tuples when you want to refer to steps by name later.
Why not just call the steps yourself
Manually scaling and then fitting works for a single split, but it breaks down in two ways. First, in cross-validation, the scaler must be refitted on each fold's training portion, which is easy to forget and leaks test information if you do. A pipeline handles this automatically, because the whole pipeline is refitted per fold. Second, at prediction time you must apply the identical preprocessing to new data; a pipeline guarantees this, while separate steps invite a mismatch.
The leakage point again
This is the concrete reason pipelines matter for correctness.
from sklearn.model_selection import cross_val_score
scores = cross_val_score(model, X, y, cv=5) # scaler refitted per fold, no leakage
Passing the whole pipeline to cross_val_score means each fold scales using only its own training rows. Passing a pre-scaled X instead would leak, because the scaling would have seen every fold's data.
Referring to steps and their parameters
With named steps you can tune parameters through the pipeline using the step__parameter syntax, which is how a pipeline plugs into hyperparameter search.
from sklearn.pipeline import Pipeline
pipe = Pipeline([("scaler", StandardScaler()), ("clf", LogisticRegression())])
pipe.set_params(clf__C=0.1)
The double underscore addresses a parameter of a specific step, so a grid search can tune the model and the preprocessing together.
Handling different column types
When numeric and categorical columns need different preprocessing, combine a ColumnTransformer (which routes columns to the right transformer) with a pipeline. That pairing is the standard structure for a real tabular workflow, and it keeps the entire process, preprocessing and model, inside one leak-proof object you can fit, evaluate, tune and save as a unit.