CatBoost (Classification) : Guide complet — Principes, Exemples et Implémentation Python
Résumé
CatBoost (Categorical Boosting) est un algorithme de gradient boosting développé par Yandex, conçu dès l’origine pour traiter nativement les variables catégorielles sans nécessiter de prétraitement manuel coûteux. Contrairement à XGBoost ou LightGBM qui exigent un encodage préalable des catégories, CatBoost intègre un mécanisme d’ordered target encoding qui encode chaque catégorie en fonction de la distribution de la variable cible observée dans les lignes qui la précèdent selon une permutation aléatoire. Cette approche élimine le problème de target leakage (fuite d’information de la cible vers les features) tout en préservant l’information prédictive des variables catégorielles. CatBoost excelle particulièrement en classification sur des jeux de données riches en variables qualitatives : données clients, transactions financières, logs applicatifs ou données démographiques.
Principe mathématique : l’Ordered Target Encoding
Le cœur de CatBoost réside dans sa méthode d’encodage des variables catégorielles, appelée ordered target encoding. Pour comprendre ce mécanisme, examinons-le étape par étape.
Soit un jeu de données contenant n observations $(x_1, y_1), (x_2, y_2), \ldots, (x_n, y_n)$, où $x_i$ inclut une variable catégorielle $C_i \in {c_1, c_2, \ldots, c_k}$ et $y_i \in {0, 1}$ est l’étiquette binaire.
Étape 1 : Permutation aléatoire
CatBoost génère plusieurs permutations aléatoires $\sigma_1, \sigma_2, \ldots, \sigma_m$ de l’ensemble des indices ${1, 2, \ldots, n}$. Chaque permutation définit un ordre dans lequel les données sont traitées :
$\sigma_j : {1, 2, \ldots, n} \rightarrow {1, 2, \ldots, n}$
Étape 2 : Encodage ordonné
Pour chaque permutation $\sigma_j$ et pour chaque ligne à la position $p$ dans cette permutation, la valeur catégorielle $C_{\sigma_j(p)}$ est remplacée par une statistique calculée uniquement sur les lignes précédentes ${\sigma_j(1), \sigma_j(2), \ldots, \sigma_j(p-1)}$ :
$$\hat{x}{\sigma_j(p)} = \frac{\sum$$}^{p-1} \mathbb{1}(C_{\sigma_j(q)} = C_{\sigma_j(p)}) \cdot y_{\sigma_j(q)} + a}{\sum_{q=1}^{p-1} \mathbb{1}(C_{\sigma_j(q)} = C_{\sigma_j(p)}) + a
où $\mathbb{1}(\cdot)$ est la fonction indicatrice, $a$ est un hyperparamètre de lissage (prior count) et le dénominateur est le nombre de fois où cette catégorie est apparue avant la position $p$.
Étape 3 : Combinaison des permutations
Les valeurs encodées sont calculées pour plusieurs permutations et combinées pour former la valeur finale utilisée par l’arbre. Cette approche garantit que la cible d’une ligne n’est jamais utilisée pour encoder ses propres features, éliminant ainsi le target leakage.
Pourquoi c’est crucial
L’encodage cible classique (mean encoding) calcule $\hat{x}_i = E[y | C = c]$ sur tout le jeu d’entraînement, ce qui crée une fuite d’information : la même ligne qui sert à calculer la statistique est ensuite prédite par le modèle. Le résultat est un surapprentissage massif sur les catégories rares. L’ordered encoding de CatBoost résout ce problème de manière élégante.
Intuition : pourquoi CatBoost change la donne
Imaginez un dataset clients avec une colonne « ville » contenant 500 valeurs distinctes. Avec un one-hot encoding classique, vous créez 500 colonnes binaires. Le modèle doit apprendre 500 poids séparés, ce qui est inefficace et nuit à la généralisation, surtout pour les villes peu représentées.
CatBoost aborde le problème différemment : au lieu de créer des colonnes, il encode chaque catégorie par une valeur numérique qui représente la tendance de la variable cible pour cette catégorie. Si Paris a un taux de conversion de 15 % et Marseille de 8 %, ces informations sont capturées directement dans la feature encodée. Mais au lieu de calculer ces taux sur l’ensemble du dataset (ce qui causerait du leakage), CatBoost les calcule sur les « données vues avant » selon une permutation aléatoire.
Cette intuition est simple mais puissante : la catégorie porte de l’information sur la cible, et on peut l’extraire sans tricher. CatBoost combine cette idée avec l’architecture du gradient boosting (addition séquentielle d’arbres faibles) pour produire un modèle à la fois précis et robuste.
Implémentation Python
Installation
pip install catboost
Classification binaire avec features catégorielles
import numpy as np
import pandas as pd
from catboost import CatBoostClassifier, Pool
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, roc_auc_score
# Données synthétiques avec variables catégorielles
np.random.seed(42)
n_samples = 5000
data = pd.DataFrame({
'ville': np.random.choice(['Paris', 'Lyon', 'Marseille', 'Bordeaux', 'Lille'], n_samples),
'secteur': np.random.choice(['tech', 'finance', 'santé', 'commerce', 'industrie'], n_samples),
'abonnement': np.random.choice(['basique', 'standard', 'premium'], n_samples),
'age': np.random.randint(18, 70, n_samples),
'revenu': np.random.normal(35000, 12000, n_samples).clip(15000, 80000),
'nb_visites': np.random.poisson(8, n_samples),
})
# Cible corrélée aux features (15 % positif)
proba = (
0.1
+ 0.08 * (data['ville'] == 'Paris').astype(float)
+ 0.06 * (data['abonnement'] == 'premium').astype(float)
+ 0.04 * (data['secteur'] == 'tech').astype(float)
+ 0.002 * (data['revenu'] - 35000) / 10000
+ 0.01 * (data['nb_visites'] - 8) / 5
)
proba = np.clip(proba, 0.02, 0.95)
y = np.random.binomial(1, proba)
# Séparation train/test
X_train, X_test, y_train, y_test = train_test_split(
data, y, test_size=0.2, random_state=42, stratify=y
)
# Identification des features catégorielles
cat_cols = ['ville', 'secteur', 'abonnement']
# Création du modèle CatBoost
model = CatBoostClassifier(
iterations=500,
learning_rate=0.05,
depth=6,
l2_leaf_reg=3.0,
loss_function='Logloss',
eval_metric='AUC',
cat_features=cat_cols, # Colonnes catégorielles directement (pas besoin d'encodage)
random_seed=42,
verbose=100,
)
# Entraînement avec Pool
train_pool = Pool(X_train, label=y_train, cat_features=cat_cols)
val_pool = Pool(X_test, label=y_test, cat_features=cat_cols)
model.fit(
train_pool,
eval_set=val_pool,
early_stopping_rounds=50,
)
# Prédictions
preds = model.predict(X_test)
pred_proba = model.predict_proba(X_test)[:, 1]
print(f"ROC AUC : {roc_auc_score(y_test, pred_proba):.4f}")
print(classification_report(y_test, preds))
Comparaison avec XGBoost
XGBoost ne gère pas nativement les variables catégorielles de type string. Il faut les encoder manuellement :
import xgboost as xgb
from sklearn.preprocessing import LabelEncoder
# Encodage manuel requis avec XGBoost
le_ville = LabelEncoder()
le_secteur = LabelEncoder()
le_abonnement = LabelEncoder()
X_train_xgb = X_train.copy()
X_train_xgb['ville'] = le_ville.fit_transform(X_train_xgb['ville'])
X_train_xgb['secteur'] = le_secteur.fit_transform(X_train_xgb['secteur'])
X_train_xgb['abonnement'] = le_abonnement.fit_transform(X_train_xgb['abonnement'])
X_test_xgb = X_test.copy()
X_test_xgb['ville'] = le_ville.transform(X_test_xgb['ville'])
X_test_xgb['secteur'] = le_secteur.transform(X_test_xgb['secteur'])
X_test_xgb['abonnement'] = le_abonnement.transform(X_test_xgb['abonnement'])
xgb_model = xgb.XGBClassifier(
n_estimators=500,
learning_rate=0.05,
max_depth=6,
reg_lambda=3.0,
eval_metric='logloss',
random_state=42,
)
xgb_model.fit(X_train_xgb, y_train)
La différence est flagrante : CatBoost accepte les colonnes catégorielles en l’état, tandis qu’XGBoost exige un encodage préalable qui peut être source d’erreurs et de fuite de données si mal appliqué.
Hyperparamètres clés
| Hyperparamètre | Description | Valeur typique |
|---|---|---|
| iterations | Nombre d’arbres (boosting rounds). Le plus influent sur la performance. | 500–2000 |
| learning_rate | Taux d’apprentissage. Plus il est faible, plus il faut d’itérations. | 0.01–0.1 |
| depth | Profondeur maximale des arbres. Contrôle la capacité du modèle. | 4–10 |
| l2_leaf_reg | Régularisation L2 sur les valeurs des feuilles. Réduit le surapprentissage. | 1–30 |
| random_strength | Facteur de randomisation pour la sélection des splits. Réduit l’overfitting. | 0.1–1.0 |
| border_count | Nombre de subdivisions pour les features numériques. Plus de bordures = plus de précision. | 32–255 |
| subsample | Fraction d’échantillons utilisée pour chaque arbre. < 1.0 active le stochastic boosting. | 0.5–1.0 |
| cat_features | Liste des colonnes catégorielles (indices ou noms). Indispensable pour l’encoding natif. | — |
Astuce de réglage
Commencez toujours par augmenter iterations avec un learning_rate modéré (0.05) et activez l’early stopping. C’est le moyen le plus sûr d’atteindre de bonnes performances sans réglage fin excessif. Ensuite, ajustez depth et l2_leaf_reg pour contrôler la complexité.
model = CatBoostClassifier(
iterations=1500,
learning_rate=0.03,
depth=6,
l2_leaf_reg=10,
subsample=0.8,
cat_features=cat_cols,
loss_function='Logloss',
eval_metric='AUC',
random_seed=42,
)
Avantages et Limites
Avantages
- Traitement natif des variables catégorielles — Aucun encodage manuel. Les colonnes de type string sont acceptées directement, ce qui simplifie les pipelines et réduit les erreurs de traitement.
- Ordered target encoding — Évite le target leakage grâce aux permutations aléatoires, offrant un encodage fiable même pour les catégories rares.
- Performances de pointe — CatBoost se classe systématiquement parmi les meilleurs algorithmes dans les compétitions Kaggle, souvent au coude-à-coude avec XGBoost et LightGBM.
- Robustesse au surapprentissage — Le mécanisme d’ordonnancement et les régularisations intégrées permettent d’obtenir de bons résultats avec peu de réglage.
- Interprétabilité — Fournit l’importance des features, les graphiques d’arbres et des outils de visualisation intégrés.
-
Support du GPU — L’entraînement peut être accéléré significativement sur GPU (paramètre
task_type='GPU').
Limites
- Vitesse d’entraînement — CatBoost est généralement plus lent que LightGBM, surtout sur des datasets très volumineux (> 1 million de lignes). L’ordered encoding ajoute une surcharge computationnelle.
- Consommation mémoire — Le calcul des statistiques ordonnées et la gestion des permutations consomment plus de RAM que les approches concurrentes.
- Moins de flexibilité — Certaines fonctionnalités avancées présentes dans XGBoost (fonctions objectives personnalisées complexes) ne sont pas supportées.
- Écosystème plus petit — La communauté et les ressources communautaires sont moins développées que celles de XGBoost.
4 Cas d’usage concrets
1. Prédiction d’attrition client (Churn)
Un opérateur téléphonique souhaite identifier les clients susceptibles de résilier leur abonnement. Les données incluent de nombreuses variables catégorielles : type de forfait, méthode de paiement, région, segment client. CatBoost gère ces catégories nativement et produit un score de risque pour chaque client, permettant des actions de rétention ciblées.
2. Détection de fraude financière
Les transactions financières contiennent des variables comme le type de marchand, le pays d’origine, le canal de paiement et le type de carte. Ces features catégorielles sont souvent très discriminantes pour la détection de fraude. L’ordered target encoding de CatBoost capture efficacement ces signaux sans surapprentissage, même pour les combinaisons rares de catégories.
3. Classification de tickets de support
Un service client reçoit des tickets avec des champs catégoriels : catégorie du produit, niveau de priorité, canal de contact, service concerné. CatBoost peut classer automatiquement ces tickets par type de résolution nécessaire, accélérant le routage vers les équipes compétentes.
4. Scoring de risque assurantiel
Les compagnies d’assurance utilisent des centaines de variables catégorielles pour évaluer le risque : type de véhicule, zone géographique, profession, type de logement. CatBoost excelle ici car il combine efficacement ces signaux catégoriels avec des variables continues (âge, sinistralité passée) dans un modèle unique et interprétable.
Voir aussi
- Algorithme Bellman-Ford : Trouver les Plus Courts Chemins avec Poids Négatifs en Python
- Maîtriser les Suites de Totients de Puissances avec Python : Guide Complet et Astuces

