W3docs

Données catégorielles

Apprenez à encoder les données catégorielles en Python avec Label Encoding, Ordinal Encoding, One-Hot Encoding et pd.get_dummies avec scikit-learn.

Les données catégorielles désignent toute donnée prenant un ensemble limité et fixe de valeurs — par exemple "red", "blue", "green" pour une colonne de couleurs, ou "low", "medium", "high" pour une note de gravité. La plupart des algorithmes de machine learning travaillent avec des nombres, donc les colonnes catégorielles doivent être converties en représentation numérique avant l'entraînement.

Ce chapitre explique les principales stratégies d'encodage, quand choisir chacune d'elles, et comment les appliquer correctement en Python avec pandas et scikit-learn sans laisser fuir d'informations de l'ensemble de test vers votre modèle.

Pourquoi l'encodage est important

Fournir des valeurs string brutes à un estimateur scikit-learn lève une ValueError. Même lorsqu'une colonne contient déjà des nombres — comme 1, 2, 3 représentant "small", "medium", "large" — un algorithme qui traite les valeurs de caractéristiques comme des nombres continus infère une fausse relation (par exemple, "large" vaut trois fois "small"). L'encodage permet de représenter la relation réelle avec précision.

Le choix de l'encodage dépend de deux questions :

  1. Existe-t-il un ordre naturel ? La couleur n'a pas d'ordre naturel (nominale). La taille de T-shirt a un ordre naturel (ordinale). L'encodage approprié préserve l'ordre quand il existe et l'ignore quand il n'existe pas.
  2. Combien de valeurs distinctes (cardinalité) la colonne contient-elle ? Les colonnes à haute cardinalité (des centaines de villes uniques, des identifiants de produits) peuvent créer des milliers de colonnes factices avec l'encodage One-Hot, ce qui nuit à la fois à la mémoire et aux performances du modèle.

Mise en place d'un jeu de données exemple

Les exemples ci-dessous utilisent un petit jeu de données vestimentaire pour que vous puissiez suivre exactement le résultat.

import pandas as pd

data = {
    "color":  ["red", "green", "blue", "green", "red"],
    "size":   ["S", "M", "L", "S", "M"],
    "price":  [10, 20, 30, 10, 20],
    "in_stock": [True, True, False, True, False],
}

df = pd.DataFrame(data)
print(df)

Résultat :

   color size  price  in_stock
0    red    S     10      True
1  green    M     20      True
2   blue    L     30     False
3  green    S     10      True
4    red    M     20     False

Label Encoding

Le Label Encoding remplace chaque catégorie par un entier. Le LabelEncoder de scikit-learn assigne les entiers par ordre alphabétique.

from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
df["color_encoded"] = le.fit_transform(df["color"])

print(df[["color", "color_encoded"]])
print("Classes:", list(le.classes_))

Résultat :

   color  color_encoded
0    red              2
1  green              1
2   blue              0
3  green              1
4    red              2
Classes: ['blue', 'green', 'red']

blue → 0, green → 1, red → 2 (ordre alphabétique).

Quand l'utiliser : Le Label Encoding est destiné à la variable cible (y), pas aux caractéristiques d'entrée. Appliqué à une colonne de caractéristique nominale, les entiers encodés impliquent un ordre qui n'existe pas, ce qui induit en erreur les modèles basés sur les arbres et est néfaste pour les modèles linéaires.

Inverser l'encodage :

decoded = le.inverse_transform([0, 1, 2])
print(decoded)  # ['blue' 'green' 'red']

Ordinal Encoding

L'Ordinal Encoding est similaire au Label Encoding mais vous permet de spécifier l'ordre exact des catégories. Utilisez-le pour les caractéristiques où l'ordre est significatif.

from sklearn.preprocessing import OrdinalEncoder

# Define the order explicitly: S < M < L
oe = OrdinalEncoder(categories=[["S", "M", "L"]])
df["size_encoded"] = oe.fit_transform(df[["size"]])

print(df[["size", "size_encoded"]])

Résultat :

  size  size_encoded
0    S           0.0
1    M           1.0
2    L           2.0
3    S           0.0
4    M           1.0

Le modèle peut désormais déduire correctement que L (2) > M (1) > S (0).

Gestion des catégories inconnues lors de la prédiction :

# Use handle_unknown='use_encoded_value' with unknown_value=-1
oe_safe = OrdinalEncoder(
    categories=[["S", "M", "L"]],
    handle_unknown="use_encoded_value",
    unknown_value=-1,
)
oe_safe.fit(df[["size"]])
print(oe_safe.transform([["XL"]]))  # [[-1.]]

One-Hot Encoding

Le One-Hot Encoding crée une colonne binaire par catégorie. Un 1 dans une colonne signifie que la ligne appartient à cette catégorie ; toutes les autres colonnes valent 0. C'est le choix standard pour les caractéristiques nominales (non ordonnées) utilisées dans les modèles linéaires, les SVM et les réseaux de neurones.

from sklearn.preprocessing import OneHotEncoder
import numpy as np

ohe = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
color_encoded = ohe.fit_transform(df[["color"]])

# Build a labelled DataFrame from the result
col_names = ohe.get_feature_names_out(["color"])
color_df = pd.DataFrame(color_encoded, columns=col_names, dtype=int)

print(color_df)

Résultat :

   color_blue  color_green  color_red
0           0            0          1
1           0            1          0
2           1            0          0
3           0            1          0
4           0            0          1

handle_unknown='ignore' remplit les catégories inconnues avec des zéros au lieu de lever une erreur lorsque de nouvelles données arrivent au moment de la prédiction.

Supprimer une colonne pour éviter la multicolinéarité

Avec trois catégories, on obtient trois colonnes binaires, mais la troisième est entièrement prévisible à partir des deux autres (blue = 1 − green − red). Ce piège des variables factices peut poser des problèmes pour les modèles linéaires. Supprimez une colonne avec drop='first' :

ohe_nodrop = OneHotEncoder(sparse_output=False, drop="first", handle_unknown="ignore")
reduced = ohe_nodrop.fit_transform(df[["color"]])
print(pd.DataFrame(reduced, columns=ohe_nodrop.get_feature_names_out(["color"]), dtype=int))

Résultat (une colonne supprimée) :

   color_green  color_red
0            0          1
1            1          0
2            0          0
3            1          0
4            0          1

Les modèles basés sur les arbres (arbres de décision, forêts aléatoires, gradient boosting) sont immunisés contre le piège des variables factices, donc supprimer une colonne est optionnel pour eux.

pd.get_dummies — L'alternative rapide avec Pandas

Pour le travail exploratoire, pd.get_dummies() est le moyen le plus rapide de faire un encodage one-hot d'un DataFrame :

dummies = pd.get_dummies(df[["color", "size"]], dtype=int)
print(dummies)

Résultat :

   color_blue  color_green  color_red  size_L  size_M  size_S
0           0            0          1       0       0       1
1           0            1          0       0       1       0
2           1            0          0       1       0       0
3           0            1          0       0       0       1
4           0            0          1       0       1       0

Limitation : pd.get_dummies() n'est pas un transformateur ajusté. Il ne peut pas garantir le même ensemble de colonnes entre les partitions d'entraînement et de test, et ne prend pas en charge handle_unknown. Pour les pipelines de production, préférez OneHotEncoder dans un Pipeline scikit-learn.

Éviter la fuite de données

La fuite de données se produit lorsque des informations de l'ensemble de test influencent la préparation des données d'entraînement. Le résultat est un score d'évaluation trop optimiste qui ne reflète pas les performances en conditions réelles.

Le schéma correct est :

  1. Diviser les données en ensembles d'entraînement et de test en premier.
  2. Ajuster tout encodeur uniquement sur l'ensemble d'entraînement.
  3. Utiliser transform() (et non fit_transform()) sur l'ensemble de test.
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder

X = df[["color", "size"]]
y = df["price"]

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4, random_state=42)

ohe = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
ohe.fit(X_train)                       # fit on training data only

X_train_enc = ohe.transform(X_train)  # transform training set
X_test_enc  = ohe.transform(X_test)   # transform test set using training-fit encoder

Pour plus de détails sur la division entraînement/test, consultez le chapitre Train/Test Split.

Utiliser un Pipeline pour combiner l'encodage avec un modèle

Un Pipeline scikit-learn enchaîne un transformateur et un estimateur. Cela garantit que l'encodeur est toujours ajusté uniquement sur les données d'entraînement, même lors de la validation croisée.

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder
from sklearn.linear_model import LinearRegression
from sklearn.compose import ColumnTransformer
from sklearn.model_selection import train_test_split

categorical_cols = ["color", "size"]
numeric_cols     = ["in_stock"]

X_full = df[categorical_cols + numeric_cols]
y_full = df["price"]

X_tr, X_te, y_tr, y_te = train_test_split(X_full, y_full, test_size=0.4, random_state=42)

preprocessor = ColumnTransformer(transformers=[
    ("ohe", OneHotEncoder(handle_unknown="ignore"), categorical_cols),
    ("pass", "passthrough", numeric_cols),
])

pipe = Pipeline(steps=[
    ("preprocessor", preprocessor),
    ("model", LinearRegression()),
])

pipe.fit(X_tr, y_tr)
print("Test predictions:", pipe.predict(X_te))

Le ColumnTransformer applique différentes étapes de prétraitement à différentes colonnes en un seul passage. Le pipeline est le schéma recommandé pour tous les workflows de machine learning en production.

Choisir le bon encodage

SituationEncodage recommandé
Variable cible (y)LabelEncoder
Caractéristique ordinale (ordre naturel existant)OrdinalEncoder avec categories explicites
Caractéristique nominale, faible cardinalitéOneHotEncoder (ou pd.get_dummies pour l'exploration)
Caractéristique nominale, haute cardinalitéEncodage cible ou encodage par fréquence (voir note ci-dessous)
Pipeline de productionOneHotEncoder dans un Pipeline / ColumnTransformer

L'encodage cible remplace chaque catégorie par la moyenne de la variable cible pour cette catégorie. Il gère bien la haute cardinalité mais est particulièrement sujet à la fuite de données — appliquez-le toujours avec des plis de validation croisée ou utilisez une implémentation de bibliothèque (par exemple, category_encoders.TargetEncoder) qui gère cela automatiquement.

Chapitres connexes

  • Scale — normaliser et standardiser les caractéristiques numériques avant la modélisation
  • Train/Test Split — diviser les données correctement avant toute étape de prétraitement
  • Linear Regression — un modèle qui bénéficie d'un encodage catégoriel approprié
  • Cross Validation — évaluer les modèles de façon fiable en combinaison avec les pipelines d'encodage
  • Confusion Matrix — mesurer les performances d'un modèle de classification après l'encodage des cibles
  • Pandas Tutorial — fondamentaux de pandas incluant la création et la manipulation de DataFrame
Was this page helpful?