scikit-learn pipeline template
Preprocessing + model + cross-validation in one pipeline.
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler
from sklearn.impute import SimpleImputer
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score
num = X.select_dtypes("number").columns
cat = X.select_dtypes("object").columns
pre = ColumnTransformer([
("num", Pipeline([("imp", SimpleImputer(strategy="median")), ("sc", StandardScaler())]), num),
("cat", Pipeline([("imp", SimpleImputer(strategy="most_frequent")), ("oh", OneHotEncoder(handle_unknown="ignore"))]), cat),
])
model = Pipeline([("pre", pre), ("clf", GradientBoostingClassifier())])
print(cross_val_score(model, X, y, cv=5, scoring="roc_auc").mean())
Why use a pipeline at all
Without a pipeline, it's easy to fill missing values or scale using the whole dataset before splitting into train and test. That leaks information from the test set into training, and your accuracy looks better than it really is. Then the model disappoints in production and nobody can work out why.
A pipeline fixes this by tying every step together. During cross-validation, each fold fits the imputer, scaler and encoder only on its own training part. As a bonus, you can save the whole thing with joblib.dump(model, "model.joblib") and the preprocessing goes along with it.
How it works
- Numeric columns get missing values filled with the median (less affected by outliers than the mean), then scaled.
- Text/category columns get missing values filled with the most common value, then one-hot encoded.
handle_unknown="ignore"means a category the model never saw in training, like a new city, won't crash it at prediction time. ColumnTransformersends each group of columns to the right steps and joins the results.- The model goes at the end, and
cross_val_scoregives you a fair score across 5 folds.
The snippet assumes X (your features as a DataFrame) and y (the target) are already loaded.
Adjusting it
- Gradient boosting doesn't need scaling. Tree models don't care about scale. It's in the template because it makes swapping in
LogisticRegressionor an SVM painless. - Imbalanced classes (say 5% churners): that's why the template scores with
"roc_auc"and not accuracy. A model that says "nobody churns" gets 95% accuracy and is useless."f1"is another good choice. - To tune it, pass the pipeline to
GridSearchCVand name parameters with the step name and a double underscore, likeclf__learning_rate. - ID columns like customer ID should be dropped from
Xbefore any of this. They're numbers, so they'd get scaled and fed to the model, which then learns nothing useful from them.