Feature Engineering : Guide Complet pour l’Ingénierie des Caractéristiques
Résumé
Le Feature Engineering (ingénierie des caractéristiques) est l’art et la science de transformer des données brutes en variables prédictives optimisées pour l’entraînement des modèles de Machine Learning. Cette discipline occupe une place centrale dans tout projet d’apprentissage automatique : selon l’adage bien connu des praticiens, « les données valent mieux que l’algorithme », et le Feature Engineering constitue précisément le pont entre des données imparfaites et des performances modèles exceptionnelles.
Ce guide complet couvrira les principes mathématiques fondamentaux de la sélection de variables (filtres, wrappers, méthodes embarquées et PCA), l’intuition pratique derrière chaque technique, une implémentation détaillée en Python avec scikit-learn, les hyperparamètres critiques, les avantages et limites de chaque approche, ainsi que quatre cas d’usage concrets illustrant l’impact du Feature Engineering en situation réelle.
Principe Mathématique du Feature Engineering et de la Sélection de Variables
Le Feature Engineering repose sur deux piliers indissociables : la création de nouvelles caractéristiques à partir des données brutes, et la sélection des variables les plus pertinentes pour le modèle. La sélection repose sur quatre grandes familles de méthodes, chacune avec ses fondements mathématiques propres.
1. Sélection par Filtre (Filter Methods)
Les méthodes par filtre évaluent chaque variable indépendamment du modèle final, en utilisant des critères statistiques univariés. Elles sont rapides et interprétables.
Corrélation de Pearson — Mesure la relation linéaire entre une variable explicative X et la variable cible Y :
r = cov(X, Y) / (σ_X · σ_Y)
où cov(X, Y) est la covariance entre X et Y, σ_X et σ_Y sont les écarts-types respectifs. Le coefficient r ∈ [-1, 1] : une valeur proche de ±1 indique une forte corrélation linéaire, tandis qu’une valeur proche de 0 suggère l’absence de relation linéaire. En Feature Engineering, on écarte typiquement les features dont |r| < 0,1, car elles apportent peu d’information prédictive.
Test du Chi-carré (χ²) — Évalue l’indépendance entre deux variables catégorielles :
χ² = Σ (Observé – Attendu)² / Attendu
où la somme porte sur toutes les cellules du tableau de contingence. Une valeur élevée de χ² (et une p-value < 0,05) indique que la variable explicative et la cible ne sont pas indépendantes : la feature est donc informative pour la classification.
Information Mutuelle (Mutual Information) — Mesure la dépendance générale (linéaire et non linéaire) entre deux variables :
I(X ; Y) = Σ p(x, y) · log(p(x, y) / (p(x) · p(y)))
où p(x, y) est la distribution conjointe et p(x), p(y) les distributions marginales. Contrairement à la corrélation de Pearson, l’information mutuelle capture toute forme de dépendance, pas seulement les relations linéaires. C’est un outil puissant pour identifier des features dont la relation avec la cible serait invisible à un simple test de corrélation.
2. Sélection par Wrapper (Wrapper Methods)
Les méthodes wrapper évaluent des sous-ensembles de variables en entraînant véritablement le modèle à chaque itération. La plus emblématique est la Recursive Feature Elimination (RFE) :
- On entraîne le modèle sur l’ensemble complet des features.
- On identifie les variables les moins importantes (coefficients les plus faibles pour un modèle linéaire, importances les plus basses pour un arbre).
- On retire ces variables et on réentraîne le modèle.
- On répète jusqu’à atteindre le nombre désiré de features.
La RFE est coûteuse en calcul (elle nécessite N entraînements successifs) mais produit généralement des sous-ensembles de variables plus performants que les filtres univariés, car elle tient compte des interactions entre features.
3. Sélection Embarquée (Embedded Methods)
Les méthodes embarquées intègrent la sélection de variables directement dans le processus d’entraînement du modèle. La plus célèbre est la régularisation L1 (Lasso) :
L = Erreur + λ · Σ |w_j|
où Erreur est la fonction de coût (par exemple, l’erreur quadratique moyenne), λ est le coefficient de régularisation, et w_j sont les coefficients du modèle. La pénalité L1 pousse certains coefficients exactement à zéro, éliminant ainsi automatiquement les variables non pertinentes. C’est une sélection de variables « gratuite », intégrée à l’apprentissage.
En comparaison, la régularisation L2 (Ridge) utilise Σ w_j² au lieu de Σ |w_j| : elle réduit l’amplitude des coefficients sans les annuler, mais ne réalise pas de sélection à proprement parler.
4. PCA — Analyse en Composantes Principales
Le PCA (Principal Component Analysis) projette les données sur les axes de plus grande variance. Mathématiquement, on calcule les valeurs propres λ_i de la matrice de covariance Σ des données. Chaque λ_i représente la variance capturée par la i-ème composante principale. En triant les composantes par λ_i décroissant et en ne gardant que les k premières, on réduit la dimensionnalité tout en préservant l’essentiel de l’information.
Le PCA est une transformation linéaire : les nouvelles composantes sont des combinaisons linéaires des variables originales. Cela signifie que l’interprétabilité est perdue — on ne sait plus quelle variable originale contribue le plus — mais le gain en réduction de dimensionalité est souvent considérable.
Intuition : L’Art du Feature Engineering
Le Feature Engineering, c’est un peu comme préparer ses ingrédients avant de cuisiner. Un bon chef ne jette pas tous les légumes crus dans la casserole — il les coupe, les assaisonne, retire ce qui n’est pas bon. Un bon data scientist fait exactement la même chose avec ses variables : il crée des interactions pertinentes, encode les catégories correctement, et garde uniquement les features qui comptent vraiment.
Prenons un exemple concret. Imaginez que vous construisiez un modèle pour prédire le prix d’un appartement. Vous disposez des surfaces des pièces. Le Feature Engineering vous suggère de créer une nouvelle variable : la surface totale (somme de toutes les pièces). Vous pourriez aussi calculer le ratio pièces/surface, ou créer un indicateur binaire « possède un balcon ». Ces variables dérivées n’existaient pas dans les données brutes, mais elles sont souvent bien plus prédictives que les variables individuelles.
La sélection de variables, quant à elle, c’est le tri sélectif. Parmi les cent features disponibles, lesquelles apportent vraiment de l’information ? Lesquelles sont redondantes ? Lesquelles ajoutent du bruit plutôt que du signal ? Un modèle entraîné sur 15 features bien choisies battra presque toujours un modèle entraîné sur 100 features dont 85 sont inutiles — et ce, pour trois raisons fondamentales :
- Réduction du surapprentissage (overfitting) : moins de paramètres à apprendre = un modèle plus généralisable.
- Accélération de l’entraînement : moins de features = moins de calculs.
- Amélioration de l’interprétabilité : il est plus facile d’expliquer un modèle à 10 variables qu’un modèle à 200.
Le curse of dimensionality (fléau de la dimensionnalité) illustre parfaitement ce phénomène : dans des espaces de très grande dimension, les données deviennent exponentiellement éparses, et les distances entre points perdent leur signification. Le Feature Engineering et la sélection de variables sont les antidotes directs à ce problème.
Implémentation Python Avec scikit-learn
Voici une implémentation complète et progressive du Feature Engineering avec la bibliothèque scikit-learn, couvrant la sélection par filtre, le wrapper RFE, l’encoding catégoriel, la création d’interactions et la construction de Pipelines reproductibles.
Sélection par Filtre : SelectKBest
from sklearn.datasets import load_breast_cancer
from sklearn.feature_selection import SelectKBest, f_classif, chi2, mutual_info_classif
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# Chargement des données
X, y = load_breast_cancer(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.2, random_state=42
)
# Sélection des k meilleures features avec le test F d'ANOVA
selector_f = SelectKBest(score_func=f_classif, k=10)
X_train_selected = selector_f.fit_transform(X_train, y_train)
X_test_selected = selector_f.transform(X_test)
# Récupération des scores et des p-values
scores = selector_f.scores_
pvalues = selector_f.pvalues_
print(f"Scores F des 10 meilleures features : {scores[:10]}")
print(f"P-values correspondantes : {pvalues[:10]}")
# Entraînement et évaluation
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_train_selected, y_train)
acc = accuracy_score(y_test, rf.predict(X_test_selected))
print(f"Précision avec SelectKBest (f_classif, k=10) : {acc:.4f}")
On peut remplacer f_classif par chi2 pour des données catégorielles non négatives, ou par mutual_info_classif pour capturer des relations non linéaires. Pour un problème de régression, on utiliserait f_regression ou mutual_info_regression.
Sélection par Wrapper : RFE avec RandomForest
from sklearn.feature_selection import RFE
from sklearn.ensemble import RandomForestClassifier
# RFE avec un classifieur RandomForest
rf_full = RandomForestClassifier(n_estimators=200, random_state=42)
rfe = RFE(estimator=rf_full, n_features_to_select=10, step=2)
rfe.fit(X_train, y_train)
# Features sélectionnées
selected_mask = rfe.support_
selected_indices = [i for i, sel in enumerate(selected_mask) if sel]
selected_features = load_breast_cancer().feature_names
print(f"Features retenues par RFE : {[selected_features[i] for i in selected_indices]}")
# Évaluation
X_train_rfe = rfe.transform(X_train)
X_test_rfe = rfe.transform(X_test)
acc_rfe = accuracy_score(y_test, rfe.predict(X_test_rfe))
print(f"Précision avec RFE (RandomForest, 10 features) : {acc_rfe:.4f}")
Le paramètre step=2 signifie que 2 features sont éliminées à chaque itération. On peut aussi utiliser step=0.1 pour éliminer 10 % des features restantes à chaque tour — plus progressif, mais plus long.
Encoding Catégoriel : OneHotEncoder et TargetEncoder
from sklearn.compose import ColumnTransformer
from sklearn.preprocessing import OneHotEncoder
from sklearn.impute import SimpleImputer
# Exemple avec des données contenant des variables catégorielles
import pandas as pd
import numpy as np
df = pd.DataFrame({
'age': [25, 34, 45, 52, 29],
'ville': ['Paris', 'Lyon', 'Paris', 'Marseille', 'Lyon'],
'niveau_etudes': ['Licence', 'Master', 'Doctorat', 'Licence', 'Master'],
'salaire': [35000, 42000, 55000, 38000, 47000]
})
# OneHotEncoder pour les variables nominales
onehot = OneHotEncoder(sparse_output=False, handle_unknown='ignore')
encoded = onehot.fit_transform(df[['ville', 'niveau_etudes']])
print(f"Variables après encodage one-hot : {onehot.get_feature_names_out().tolist()}")
# ColumnTransformer pour appliquer différents traitements par type de colonne
preprocessor = ColumnTransformer(
transformers=[
('num', SimpleImputer(strategy='median'), ['age']),
('cat', OneHotEncoder(sparse_output=False, handle_unknown='ignore'), ['ville', 'niveau_etudes'])
],
remainder='drop'
)
X_processed = preprocessor.fit_transform(df)
print(f"Forme après prétraitement : {X_processed.shape}")
Pour le TargetEncoder (encoding selon la moyenne de la cible par catégorie), on utilise la bibliothèque category_encoders :
import category_encoders as ce
# TargetEncoder : encode chaque catégorie par la moyenne de la cible
target_enc = ce.TargetEncoder(cols=['ville', 'niveau_etudes'])
X_train_encoded = target_enc.fit_transform(X_train_df, y_train)
X_test_encoded = target_enc.transform(X_test_df)
Le TargetEncoder est particulièrement utile pour les variables catégorielles à cardinalité élevée (plus de 50 catégories), où le OneHotEncoder produirait une explosion dimensionnelle.
Création d’Interactions : PolynomialFeatures
from sklearn.preprocessing import PolynomialFeatures
# Création de caractéristiques polynomiales (interactions et puissances)
poly = PolynomialFeatures(degree=2, include_bias=False, interaction_only=False)
X_poly = poly.fit_transform(X_train_selected[:, :5])
print(f"Forme après interaction polynomiale : {X_poly.shape}")
print(f"Nouvelles features créées : {poly.get_feature_names_out().tolist()[:10]}")
# interaction_only=True ne crée que les produits croisés (x1*x2), pas les carrés (x1²)
poly_interactions = PolynomialFeatures(degree=2, include_bias=False, interaction_only=True)
X_inter = poly_interactions.fit_transform(X_train_selected[:, :5])
print(f"Interactions seules : {X_inter.shape}")
Les interactions polynomiales permettent au modèle linéaire de capturer des relations non linéaires. Attention : le nombre de features croît de façon combinatoire — avec 10 variables et un degré 2, on passe de 10 à 54 features (10² + combinaisons). C’est précisément le curse of dimensionality en action.
Pipeline Complet et Reproductible
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
# Pipeline complet : prétraitement → sélection → scaling → classification
pipeline = Pipeline([
('imputation', SimpleImputer(strategy='median')),
('selection', SelectKBest(score_func=f_classif, k=15)),
('scaling', StandardScaler()),
('classification', LogisticRegression(
penalty='l1', solver='liblinear', C=1.0, max_iter=1000
))
])
pipeline.fit(X_train, y_train)
acc_pipeline = accuracy_score(y_test, pipeline.predict(X_test))
print(f"Précision du pipeline complet : {acc_pipeline:.4f}")
# Quelles features ont été retenues ?
selected_indices = pipeline.named_steps['selection'].get_support()
feature_names = load_breast_cancer().feature_names
selected_names = [name for name, sel in zip(feature_names, selected_indices) if sel]
print(f"Features finales du pipeline : {selected_names}")
Le Pipeline garantit que toutes les transformations sont appliquées dans le bon ordre et évite les fuites de données (data leakage) : le fit du SelectKBest ne voit que les données d’entraînement, jamais les données de test.
Hyperparamètres Critiques du Feature Engineering
k (nombre de features à conserver)
C’est l’hyperparamètre le plus influent. Trop peu de features (k < 5) : le modèle sous-ajuste et manque d’information. Trop de features (k > 50) : le risque de surapprentissage augmente, et le temps de calcul explose. La règle empirique recommande de commencer avec k entre 10 et 30, puis d’ajuster par validation croisée.
threshold_variance (seuil de variance)
La sélection par variance élimine les features dont la variance est inférieure à un seuil. Par défaut dans scikit-learn, VarianceThreshold(threshold=0.0) ne supprime que les features constantes. Un seuil de 0,01 à 0,05 est raisonnable pour éliminer les variables quasi-constantes qui n’apportent aucune information discriminante.
encoding_strategy (stratégie d’encodage)
Le choix de la méthode d’encoding impacte directement les performances :
- OneHotEncoder : idéal pour les variables nominales à faible cardinalité (< 20 catégories). Crée une colonne binaire par catégorie.
- OrdinalEncoder : pour les variables ordinales (ex. : « petit », « moyen », « grand »). Préserve l’ordre.
- TargetEncoder : pour les variables à haute cardinalité (> 50 catégories). Encode chaque catégorie par la moyenne de la cible. Attention au risque de data leakage : utiliser avec validation croisée.
- BinaryEncoder / HashingEncoder : compromis pour les cardinalités intermédiaires. Convertit les catégories en représentation binaire ou hachée.
regularization_alpha (coefficient de régularisation)
Dans les méthodes embarquées (Lasso, ElasticNet), le paramètre C (inverse de α dans scikit-learn) contrôle l’intensité de la pénalité :
- C = 10 (α faible) : pénalité douce, presque toutes les variables sont conservées.
- C = 1.0 : équilibre standard.
- C = 0.1 (α fort) : pénalité sévère, seules les features les plus importantes subsistent.
- C = 0.01 : pénalité très forte, sélection drastique.
Le choix optimal se détermine par validation croisée sur une grille de valeurs logarithmiques : C ∈ [0.001, 0.01, 0.1, 1.0, 10.0].
Avantages et Limites du Feature Engineering
Avantages
- Amélioration significative des performances : un Feature Engineering bien mené peut augmenter la précision de 10 à 30 % par rapport à l’utilisation brute des données. C’est souvent le levier le plus efficace avant même de changer de modèle.
- Réduction du temps d’entraînement : moins de features signifie moins de calculs. Sur des jeux de données massifs, la réduction de 1 000 à 50 features peut diviser le temps d’entraînement par 20.
- Meilleure interprétabilité : un modèle avec 10 features bien choisies est beaucoup plus facile à expliquer à des parties prenantes non techniques qu’un modèle avec 500 features.
- Réduction du surapprentissage : en éliminant le bruit et les variables redondantes, le modèle généralise mieux sur des données invisibles.
- Adaptabilité au domaine métier : le Feature Engineering permet d’injecter de la connaissance experte dans le modèle (ex. : créer un ratio dette/revenu en crédit scoring).
Limites
- Coût en temps et expertise : un Feature Engineering de qualité nécessite une compréhension approfondie du domaine, une exploration minutieuse des données, et des itérations nombreuses. C’est souvent l’étape la plus chronophage d’un projet ML.
- Risque de data leakage : si les transformations (normalisation, TargetEncoder, etc.) sont calculées sur l’ensemble des données avant la division train/test, le modèle « triche » en accédant à l’information du test. L’usage de Pipelines est essentiel pour éviter ce piège.
- Perte d’interprétabilité avec le PCA : les composantes principales sont des combinaisons linéaires obscures des variables originales. On ne sait plus quelles variables contribuent réellement.
- Sur-optimisation sur le jeu de validation : à force de tester différentes combinaisons de features, on risque de s’adapter au bruit spécifique du jeu de validation plutôt qu’au signal général.
- Instabilité temporelle : les relations entre features et cible peuvent évoluer dans le temps (concept drift). Un Feature Engineering optimal aujourd’hui peut devenir sous-optimal dans six mois.
4 Cas d’Usage Concrets du Feature Engineering
Cas d’Usage 1 : Crédit Scoring — Feature Engineering Financier
Dans le domaine du crédit bancaire, les données brutes comprennent le revenu, le montant du prêt, l’ancienneté dans l’emploi, le nombre de crédits en cours, etc. Le Feature Engineering crée des ratios métier essentiels :
- Ratio d’endettement = mensualité du prêt / revenu mensuel
- Stabilité professionnelle = années d’ancienneté / âge
- Diversification du crédit = nombre de types de crédits différents
- Score de risque combiné = pondération des incidents de paiement passés
Une sélection par Lasso (régularisation L1) élimine ensuite automatiquement les variables redondantes. Résultat typique : le modèle passe de 45 variables brutes à 12 features sélectionnées, avec une baisse du taux de faux positifs de 15 %.
Cas d’Usage 2 : Détection de Fraude — Interactions Temporelles
En détection de fraude à la carte bancaire, les données brutes sont les transactions avec leur montant, lieu, heure, et type de commerçant. Le Feature Engineering crée des features temporelles et contextuelles :
- Fréquence des transactions : nombre de transactions dans les dernières 24 heures
- Écart géographique : distance entre la transaction actuelle et la précédente
- Écart de montant : différence entre le montant actuel et la moyenne des 30 derniers jours
- Heure inhabituelle : la transaction a-t-elle lieu à une heure où le client ne transactionne habituellement pas ?
- Nouveau marchand : le commerçant est-il inconnu dans l’historique du client ?
L’information mutuelle (mutual_info_classif) est particulièrement efficace dans ce contexte, car la relation entre ces features et la fraude est hautement non linéaire.
Cas d’Usage 3 : Pricing Immobilier — Variables Géographiques et Polynomial Features
Pour prédire le prix d’un bien immobilier, les données brutes incluent la surface, le nombre de pièces, l’année de construction, le quartier, et les coordonnées GPS. Le Feature Engineering enrichit considérablement le jeu de données :
- Prix au m² du quartier : moyenne des prix des ventes récentes dans le même arrondissement
- Distance aux transports : kilomètres jusqu’à la station de métro la plus proche
- Indice de rénovation = (année actuelle – année de construction) avec bornes
- Interactions polynomiales : surface × nombre de pièces (captures la taille moyenne des pièces)
- Encodage ordinal du standing : « économique », « standard », « premium », « luxe »
Un PolynomialFeatures de degré 2 sur les variables numériques, combiné à un TargetEncoder pour les arrondissements, permet de capturer des interactions complexes entre localisation et caractéristiques du bien.
Cas d’Usage 4 : Diagnostic Médical — Sélection de Biomarqueurs
En diagnostic médical assisté par IA, on dispose de centaines de biomarqueurs sanguins, d’indicateurs vitaux et de données démographiques. Le défi est d’identifier les combinaisons les plus discriminantes pour une pathologie donnée.
Le Feature Engineering crée des indices composites :
- Indice inflammatoire = combinaison de CRP, leucocytes et vitesse de sédimentation
- Score métabolique = glucose + HbA1c + insulinémie
- Ratio hépatique = ASAT / ALAT
- Indicateur de fragilité = albumine + créatinine + indice de masse corporelle
La méthode RFE avec un classifieur de type Gradient Boosting sélectionne itérativement les 20 biomarqueurs les plus informatifs parmi les 200 initiaux. Cette approche embarquée tient compte des interactions complexes entre biomarqueurs que les filtres univariés manqueraient.
Voir Aussi
- Explorer les Polynômes Dynamiques avec Python : Guide Complet et Applications Pratiques
- Maîtriser l’Opérateur Floor en Python : La Révolution des Calculs Arithmétiques

