Maîtriser ColumnTransformer, imputers, scalers et encoders pour des modèles ML reproductibles.
En production, 80 % des bugs ML viennent d'une fuite de données (data leakage) durant le preprocessing. Le piège classique : un débutant calcule la moyenne pour imputer sur l'ensemble du dataset AVANT de séparer train/test. Résultat : le test contient indirectement de l'information du train via la moyenne — l'évaluation est faussée.
Selon la documentation officielle scikit-learn (User Guide section 6.1, version 1.4) : « Pipeline can be used to chain multiple estimators into one. This is useful as there is often a fixed sequence of steps in processing the data, for example feature selection, normalization and classification ».
Source : scikit-learn.org/stable/modules/compose.html (consultée 2026-05-27).
Un Pipeline est une liste de tuples (nom, estimateur). Tous les estimateurs intermédiaires doivent être des transformers (méthode fit_transform), et le dernier peut être un estimator final (predict).
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42, stratify=y)
pipe = Pipeline([
('scaler', StandardScaler()),
('clf', LogisticRegression(max_iter=1000, C=0.1))
])
pipe.fit(X_train, y_train) # fit_transform sur scaler puis fit sur clf
print(pipe.score(X_test, y_test)) # transform sur scaler puis predict
Lors du fit, le scaler calcule moyenne et écart-type UNIQUEMENT sur X_train. Lors du predict, ces mêmes valeurs sont réutilisées sur X_test : aucune fuite possible.
La vraie vie présente toujours un mélange de variables numériques, catégorielles, dates, textes. ColumnTransformer permet d'appliquer une transformation différente à chaque sous-ensemble de colonnes, en parallèle, puis de concaténer les sorties.
| Type de variable | Transformation typique | Sklearn class |
|---|---|---|
| Numérique continue | Imputation médiane + StandardScaler | SimpleImputer + StandardScaler |
| Catégorielle basse card. (<15) | Imputation mode + OneHotEncoder | SimpleImputer(strategy='most_frequent') + OneHotEncoder |
| Catégorielle haute card. (>100) | TargetEncoder | TargetEncoder (sklearn ≥ 1.3) |
| Ordinale | OrdinalEncoder avec ordre explicite | OrdinalEncoder(categories=[...]) |
| Date | Extraction features (jour semaine, mois, lag) | FunctionTransformer |
from sklearn.compose import ColumnTransformer
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.ensemble import RandomForestClassifier
num_cols = ['Age', 'Fare']
cat_cols = ['Pclass', 'Sex', 'Embarked']
num_pipe = Pipeline([
('imputer', SimpleImputer(strategy='median')),
('scaler', StandardScaler())
])
cat_pipe = Pipeline([
('imputer', SimpleImputer(strategy='most_frequent')),
('encoder', OneHotEncoder(handle_unknown='ignore', sparse_output=False))
])
preprocessor = ColumnTransformer([
('num', num_pipe, num_cols),
('cat', cat_pipe, cat_cols)
], remainder='drop')
model = Pipeline([
('prep', preprocessor),
('clf', RandomForestClassifier(n_estimators=300, random_state=42))
])
model.fit(X_train, y_train)
Ce pattern est le standard industriel : il est utilisé par 92 % des notebooks gold-medal Kaggle (analyse Meta-Kaggle 2024).
| Imputer | Cas d'usage | Coût compute |
|---|---|---|
SimpleImputer(strategy='mean') | MCAR numérique symétrique | O(1) |
SimpleImputer(strategy='median') | MCAR numérique asymétrique (présence d'outliers) | O(n log n) |
SimpleImputer(strategy='most_frequent') | Catégoriel | O(n) |
KNNImputer(n_neighbors=5) | MAR — utilise les k plus proches voisins | O(n²) |
IterativeImputer() | MAR — Bayesian Ridge multivariée (MICE-like) | O(n × p × iter) |
SimpleImputer dans un Pipeline pour que le fit ne voie que le train.
Tous les algorithmes ML ne nécessitent PAS un scaling. Comprendre cette distinction évite du temps perdu.
| Algorithme | Scaling nécessaire ? | Raison |
|---|---|---|
| Régression linéaire / logistique régularisée (Lasso, Ridge) | OUI | Pénalité L1/L2 sensible aux échelles |
| SVM (kernel RBF, polynomial) | OUI | Distance euclidienne dans l'espace kernel |
| KNN, K-Means | OUI | Distance euclidienne directe |
| Réseaux de neurones | OUI | Convergence du gradient + saturation activations |
| Random Forest, Gradient Boosting (XGBoost, LightGBM) | NON | Splits basés sur des seuils, invariant par transformation monotone |
| Naive Bayes | NON | Probabilités conditionnelles, pas distances |
StandardScaler centre-réduit avec moyenne 0 et variance 1. Sensible aux outliers : un point extrême déforme la distribution.
RobustScaler utilise la médiane et l'IQR (Interquartile Range). Recommandé dès que les données contiennent des outliers visibles (boxplot, IQR test).
joblib.dump(scaler, 'scaler.pkl'). Au runtime, chargez-le pour transformer les nouvelles données avec EXACTEMENT les mêmes paramètres que lors de l'entraînement. Toute incohérence = production drift garanti.
Pour une variable à k modalités, génère k colonnes binaires (ou k-1 avec drop='first' pour éviter la colinéarité parfaite en régression linéaire).
Disponible nativement depuis sklearn 1.3 (juin 2023). Remplace chaque modalité par la moyenne (ou taux) de la cible pour cette modalité. Risque de fuite : utiliser le cv intégré qui effectue un encoding cross-validé hors du fold courant.
from sklearn.preprocessing import TargetEncoder
encoder = TargetEncoder(target_type='binary', cv=5, smooth='auto')
X_train_enc = encoder.fit_transform(X_train_cat, y_train)
X_test_enc = encoder.transform(X_test_cat)
Génère interactions et puissances d'ordre d. Attention à l'explosion combinatoire : degree=3 sur 20 features = ~1 700 colonnes.
Transforme une variable continue en classes (quantile, uniform, kmeans). Utile pour traiter des relations fortement non-linéaires en régression linéaire.
Réduction de dimension après encoding pour limiter le sur-apprentissage. PCA exige un scaling préalable (sinon la variance d'une feature en milliers domine celles en unités).
Pipeline.named_steps et tester sur un sample de productionLa leçon suivante est également gratuite. Découvrez-la sans inscription.
Leçon 2 — Continuer →Choisis quels cookies tu acceptes — modifiable à tout moment.