scikit-learn Pipelines & Workflow
The estimator API, data leakage, and how Pipeline, ColumnTransformer, and GridSearchCV turn your workflow into one tunable, leak-proof object.
You now know the workflow (split → fit → predict → evaluate) and you've seen that preprocessing like scaling must be fit on training data only. Doing that by hand gets error-prone fast — real datasets need imputation and scaling and encoding, each with its own fit-on-train rule. scikit-learn's answer is the Pipeline: bundle every step into a single object that behaves like one model. This lesson is the glue that holds the rest of the course together.
One interface: fit, predict, transform
Everything in scikit-learn is an estimator sharing a tiny, consistent API:
est.fit(X_train, y_train)— learn from data. Models learn parameters; preprocessors learn statistics (a scaler learns means, an encoder learns categories).est.predict(X)— for models (predictors): output labels or numbers.est.transform(X)— for transformers (preprocessors): output a modified copy of the data.est.fit_transform(X)— fit then transform in one call (train data only!).
Because every scaler, encoder, imputer, and model speaks this same language, you can swap a KNN for a random forest — or a MinMax scaler for a standard one — without changing the surrounding code. That uniformity is what makes pipelines possible.
Leakage: the silent score inflator
Data leakage is when information from the test set sneaks into training. The model's scores look great, then reality disappoints. The most common leaks are mundane:
- Scaling with statistics from all rows — the test set's mean has leaked into training.
- Imputing missing values using the full dataset — same problem.
- Tuning hyperparameters against the test set — after enough peeks, the test set is effectively memorized.
The rule that prevents leakage
Fit anything that learns from data — scalers, imputers, encoders, models — on the training split only. Then apply (transform) it, unchanged, to the test split. Never call fit, or fit_transform, on test data.
Pipeline: preprocessing and model as one estimator
A Pipeline chains transformers and ends with a model. When you call
fit, it fit-transforms each step on training data in sequence; when you
call predict or score, it only transforms — the fit-on-train rule is
enforced automatically:
The cross_val_score call is doing something subtle and important. A single
train/test split can be lucky or unlucky; k-fold cross-validation splits
the training data into k parts, trains on k−1 and validates on the remaining
one, rotating k times — like judging a student on both a midterm and a final
instead of one exam. The mean of the k scores is a far more robust estimate.
And because we passed the pipeline, the scaler is refit inside every fold —
zero leakage, zero manual bookkeeping.
Mixed columns: ColumnTransformer
Real tables mix numeric columns (scale them, impute with the median) and
categorical columns (impute with the most frequent value, one-hot encode
them). ColumnTransformer routes each group of columns through its own
mini-pipeline:
Four messy columns in; seven clean numeric columns out — missing values
filled, numerics standardized, categories expanded into one-hot indicator
columns. handle_unknown="ignore" keeps predictions from crashing if a
category appears at test time that training never saw.
Tuning the whole pipeline: GridSearchCV
Hyperparameters (like KNN's n_neighbors) shouldn't be tuned against the
test set. GridSearchCV tries every parameter combination using
cross-validation inside the training data, then refits the best one. Name
pipeline steps and address their parameters with a double underscore, as in
knn__n_neighbors:
That's 4 × 2 = 8 combinations, each cross-validated 3 times — 24 fits, all
leak-free because scaling happens inside each fold. On real projects the grid
is bigger and you'd add n_jobs=-1 to parallelize across CPU cores (and
consider RandomizedSearchCV when the grid explodes).
The complete modern workflow, then, in one breath: split → build preprocessor + model into a pipeline → grid-search with CV on the training set → evaluate once on the test set. This skeleton carries you through nearly every tabular ML problem.
Check your understanding
Q1.Which method does a transformer (like StandardScaler) use to modify data after fitting?
Q2.You call scaler.fit_transform on the ENTIRE dataset before splitting. What went wrong?
Q3.Why is cross_val_score(pipeline, ...) safer than scaling manually and then cross-validating the bare model?
Q4.In a pipeline with a step named "knn", how do you refer to its n_neighbors in a GridSearchCV param grid?
Q5.What does ColumnTransformer add on top of Pipeline?
Exercise: Build a leak-proof pipeline for messy data
Create a synthetic 200-row DataFrame with two numeric columns (income,
age — make the label depend on income), one categorical column (city),
and about 15% missing values in income. Build a full pipeline —
ColumnTransformer preprocessing plus a KNeighborsClassifier — and tune
n_neighbors and weights with a small GridSearchCV. Report the best CV
score and the final test accuracy.
Next up: before any pipeline runs, you have to understand your data — EDA and feature engineering, where most real-world accuracy is won.