Bagging : Guide Complet — Bootstrap Aggregating

Bagging : Guide Complet — Bootstrap Aggregating

Bagging : Guide Complet — Bootstrap Aggregating

Résumé

Le Bagging (acronyme de Bootstrap Aggregating) est l’une des techniques d’ensemble les plus fondamentales et les plus efficaces en apprentissage automatique. Introduit par Leo Breiman en 1996, le Bagging réduit la variance d’un modèle prédictif en entraînant de multiples versions du même algorithme sur des sous-échantillons bootstrap tirés du jeu de données d’entraînement, puis en agrégeant leurs prédictions par vote majoritaire (classification) ou par moyenne (régression). Cette méthode est particulièrement puissante lorsqu’elle est appliquée à des modèles à forte variance, comme les arbres de décision profonds. Comprendre le Bagging est essentiel pour quiconque souhaite maîtriser les méthodes d’ensemble modernes.


Principe mathématique du Bagging

Échantillonnage bootstrap

Le fondement mathématique du Bagging repose sur la technique du bootstrap, introduite par Bradley Efron en 1979. Le principe est le suivant : à partir d’un jeu de données d’entraînement contenant N observations, on génère B échantillons bootstrap. Chaque échantillon bootstrap est obtenu par un échantillonnage avec remplacement de taille N parmi les N observations originales.

La propriété mathématique clé de cet échantillonnage est la suivante : la probabilité qu’une observation donnée soit exclue d’un échantillon bootstrap particulier est :

P(observation exclue) = (1 – 1/N)^N

Lorsque N est suffisamment grand, cette probabilité converge vers une constante remarquable :

(1 – 1/N)^N → 1/e ≈ 0,3679 ≈ 37 %

Cela signifie qu’environ 37 % des observations originales ne sont jamais présentes dans un échantillon bootstrap donné. Ces observations, absentes de l’entraînement d’un modèle particulier, constituent ce qu’on appelle les données out-of-bag (OOB). Elles jouent un rôle crucial pour l’évaluation interne du modèle, sans nécessiter de jeu de validation séparé.

Inversement, environ 63 % des observations sont présentes dans chaque échantillon bootstrap, certaines apparaissant plusieurs fois. Cette redondance naturelle confère à chaque modèle une perspective légèrement différente sur les données.

Agrégation des prédictions

Une fois les B modèles entraînés sur leurs échantillons bootstrap respectifs, le Bagging agrège leurs prédictions de la manière suivante :

En classification : vote majoritaire

Pour une nouvelle observation x, chaque modèle b produit une prédiction de classe C_b(x). La prédiction finale est la classe qui reçoit le plus de votes :

C_final(x) = argmax_c Σ_b I(C_b(x) = c)

I(·) est la fonction indicatrice qui vaut 1 si la condition est vraie, 0 sinon. Chaque modèle contribue équitablement au vote, sans pondération particulière.

En régression : moyenne arithmétique

Pour une nouvelle observation x, chaque modèle b produit une prédiction numérique f_b(x). La prédiction finale est la moyenne de toutes les prédictions :

f_final(x) = (1/B) Σ_b f_b(x)

Cette moyenne simple est à la fois élégante et efficace : elle lisse les erreurs individuelles de chaque modèle.

Réduction de variance : l’analyse théorique

Le bénéfice fondamental du Bagging est la réduction de variance. Pour comprendre ce mécanisme, considérons un ensemble de k modèles dont les prédictions ont chacune une variance σ², et dont la corrélation par paire est ρ (rho).

La variance de la moyenne de ces k modèles corrélés s’exprime ainsi :

Var(moyenne_de_k_modèles) = ρ·σ² + (1 – ρ)·σ²/k

Cette formule révèle plusieurs insights essentiels :

  1. Quand k → ∞ (beaucoup de modèles) : le second terme tend vers zéro, et la variance converge vers ρ·σ². La variance résiduelle est donc proportionnelle à la corrélation entre les modèles. Si les modèles sont parfaitement corrélés (ρ = 1), le Bagging n’apporte aucun bénéfice. C’est pourquoi la diversité des modèles est cruciale.
  2. Quand ρ est faible (modèles très diversifiés) : la variance est considérablement réduite, d’un facteur pouvant atteindre k. C’est la situation idéale que le bootstrap cherche à créer en présentant à chaque modèle un sous-ensemble différent des données.
  3. Le compromis : idéalement, on veut des modèles individuellement performants mais aussi peu corrélés que possible. Le bootstrap réalise ce compromis naturellement : chaque modèle voit 63 % des données, mais pas les mêmes 63 %.

En résumé, le Bagging est d’autant plus efficace que les modèles de base sont instables (c’est-à-dire sensibles aux petites variations du jeu d’entraînement). Les arbres de décision profonds sont précisément dans cette catégorie : une légère modification des données d’entraînement peut radicalement changer la structure de l’arbre. C’est pour cette raison que le Bagging excelle avec les arbres de décision, et c’est également le principe fondateur des forêts aléatoires (Random Forests).


Intuition : la sagesse de la foule

Pour comprendre le Bagging de manière intuitive, imaginez la situation suivante : au lieu de poser la même question complexe à une seule personne très intelligente mais parfois erratique, on pose cette même question à cent personnes légèrement différentes et on retient la réponse majoritaire.

Cette analogie capture l’essence du Bagging :

  • Une seule personne intelligente mais erratique = un modèle puissant mais à forte variance (un arbre de décision profond, par exemple). Il peut donner d’excellentes réponses, mais il est aussi susceptible de se tromper de manière spectaculaire selon les données qu’il a vues pendant son entraînement.
  • Cent personnes légèrement différentes = cent modèles du même type, mais chacun entraîné sur un sous-échantillon légèrement différent des données. Chacun fait des erreurs, mais pas les mêmes erreurs.
  • La réponse majoritaire = l’agrégation par vote ou par moyenne. Quand les erreurs sont indépendantes ou faiblement corrélées, elles s’annulent mutuellement, et la réponse collective est plus fiable que n’importe quelle réponse individuelle.

Ce phénomène est bien connu en science sous le nom de sagesse de la foule (wisdom of crowds). En 1906, Francis Galton a démontré lors d’une foire agricole que la moyenne des estimations de poids d’un bœuf par 787 villageois différait de moins de 1 % du poids réel. Aucun individu n’avait été aussi précis que la foule dans son ensemble.

Le Bagging applique exactement ce principe aux modèles prédictifs : la diversité des perspectives compense les faiblesses individuelles, et l’agrégation produit une prédiction plus robuste et plus fiable que celle de n’importe quel modèle pris isolément.


Implémentation Python avec scikit-learn

Voici une implémentation complète du Bagging avec scikit-learn, utilisant un DecisionTreeClassifier (stump d’arbre de décision, c’est-à-dire un arbre de profondeur 1) comme modèle de base. Nous comparerons les performances du Bagging avec celles d’un arbre de décision unique.

# ===========================================================================
# 130-bagging-implementation.py
# Illustration du Bagging avec scikit-learn
# ===========================================================================

import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.metrics import accuracy_score, classification_report
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt

# ---------------------------------------------------------------------------
# 1. Génération d'un jeu de données synthétique
# ---------------------------------------------------------------------------
X, y = make_classification(
    n_samples=2000,
    n_features=20,
    n_informative=10,
    n_redundant=5,
    n_classes=2,
    flip_y=0.1,          # 10% de bruit dans les étiquettes
    class_sep=0.7,
    random_state=42
)

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

print(f"Jeu d'entraînement : {X_train.shape[0]} exemples")
print(f"Jeu de test       : {X_test.shape[0]} exemples")
print(f"Repartition des classes : {np.bincount(y_train)}")
print()

# ---------------------------------------------------------------------------
# 2. Arbre de decision unique (reference)
# ---------------------------------------------------------------------------
arbre_unique = DecisionTreeClassifier(
    max_depth=None,       # arbre complet (non elague)
    random_state=42
)
arbre_unique.fit(X_train, y_train)

train_acc_arbre = accuracy_score(y_train, arbre_unique.predict(X_train))
test_acc_arbre = accuracy_score(y_test, arbre_unique.predict(X_test))

print("=" * 60)
print("ARBRE DE DECISION UNIQUE (reference)")
print(f"  Precision entraînement : {train_acc_arbre:.4f}")
print(f"  Precision test         : {test_acc_arbre:.4f}")
print(f"  Surapprentissage       : {train_acc_arbre - test_acc_arbre:.4f}")
print()

# ---------------------------------------------------------------------------
# 3. BaggingClassifier avec DecisionTreeStump (profondeur = 1)
# ---------------------------------------------------------------------------
bagging = BaggingClassifier(
    estimator=DecisionTreeClassifier(max_depth=1, random_state=42),
    n_estimators=100,
    max_samples=1.0,       # 100% des donnees (tirees avec remplacement)
    max_features=1.0,      # toutes les caracteristiques
    bootstrap=True,
    bootstrap_features=False,
    oob_score=True,        # activation du score out-of-bag
    random_state=42
)
bagging.fit(X_train, y_train)

oob_score_bagging = bagging.oob_score_
test_acc_bagging = accuracy_score(y_test, bagging.predict(X_test))

print("=" * 60)
print("BAGGING (100 stumps, out-of-bag active)")
print(f"  Score OOB              : {oob_score_bagging:.4f}")
print(f"  Precision test         : {test_acc_bagging:.4f}")
print()

# ---------------------------------------------------------------------------
# 4. Bagging avec arbre de decision PROFOND (non elague)
# ---------------------------------------------------------------------------
bagging_profond = BaggingClassifier(
    estimator=DecisionTreeClassifier(max_depth=None, random_state=42),
    n_estimators=100,
    max_samples=1.0,
    max_features=1.0,
    bootstrap=True,
    oob_score=True,
    random_state=42
)
bagging_profond.fit(X_train, y_train)

oob_profond = bagging_profond.oob_score_
test_profond = accuracy_score(y_test, bagging_profond.predict(X_test))

print("=" * 60)
print("BAGGING (100 arbres profonds, out-of-bag active)")
print(f"  Score OOB              : {oob_profond:.4f}")
print(f"  Precision test         : {test_profond:.4f}")
print()

# ---------------------------------------------------------------------------
# 5. Comparaison du surapprentissage
# ---------------------------------------------------------------------------
train_profond = accuracy_score(y_train, bagging_profond.predict(X_train))
gap_arbre = train_acc_arbre - test_acc_arbre
gap_bagging = train_profond - test_profond

print("=" * 60)
print("COMPARAISON DU SURAPPRENTISSAGE (ecart train - test)")
print(f"  Arbre unique  : {gap_arbre:.4f}")
print(f"  Bagging (profond) : {gap_bagging:.4f}")
print()

# Le Bagging reduit significativement le surapprentissage car
# chaque arbre voit un sous-ensemble different des donnees,
# et l'agregation par vote lisse les predictions excessives.

Analyse des résultats

Ce code illustre plusieurs phénomènes importants :

  • L’arbre unique montre typiquement un fort surapprentissage : il atteint une précision proche de 100 % sur le jeu d’entraînement, mais ses performances sur le jeu de test sont nettement inférieures.
  • Le Bagging avec des stumps (arbres de profondeur 1) produit des modèles individuels faibles, mais leur agrégation donne un résultat solide grâce à la diversité des sous-échantillons.
  • Le Bagging avec des arbres profonds est la configuration la plus puissante. Chaque arbre est susceptible de surapprendre, mais comme chacun surapprend différemment (sur des données différentes), le vote majoritaire lisse ces excès et produit un modèle généralisable.
  • Le score out-of-bag fournit une estimation honnête de la performance généralisée sans nécessiter de jeu de validation séparé. Il est calculé en évaluant chaque observation sur les modèles qui ne l’ont jamais vue lors de l’entraînement (les fameux 37 % exclus du bootstrap).

Les hyperparamètres clés du Bagging

Le BaggingClassifier de scikit-learn expose plusieurs hyperparamètres essentiels qu’il est indispensable de comprendre et de tuner correctement.

n_estimators (entier, défaut : 10)

Nombre de modèles dans l’ensemble. Plus ce nombre est élevé, plus la variance est réduite. Cependant, les rendements sont décroissants : au-delà de 100 estimateurs, les gains marginaux deviennent souvent négligeables. En pratique, on recommande de commencer avec 50 à 200 estimateurs et d’ajuster selon la complexité du problème.

max_samples (entier ou flottant, défaut : 1.0)

Nombre ou proportion d’échantillons tirés pour chaque apprentissage individuel. Par défaut (max_samples=1.0), on tire N échantillons avec remplacement (bootstrap classique). En réduisant cette valeur (par exemple max_samples=0.8), on augmente la diversité entre les modèles, ce qui peut être bénéfique si les modèles de base sont trop corrélés. Attention : trop réduire max_samples peut diminuer la qualité de chaque modèle individuel.

max_features (entier ou flottant, défaut : 1.0)

Nombre ou proportion de caractéristiques tirées aléatoirement pour entraîner chaque modèle. Par défaut, toutes les caractéristiques sont utilisées. En réduisant max_features, on augmente la diversité des modèles au prix d’une légère dégradation de chaque modèle individuel. C’est le paramètre clé qui distingue le Bagging classique des Random Forests, où max_features est généralement fixé à sqrt(n_features).

bootstrap (booléen, défaut : True)

Détermine si les échantillons sont tirés avec remplacement (True) ou sans remplacement (False). Le Bootstrapping est la configuration standard du Bagging. Quand bootstrap=False, on parle parfois de Pasting : chaque échantillon ne contient jamais deux fois la même observation. Le Pasting produit des modèles moins diversifiés que le Bagging, mais peut être utile quand on dispose de très grands jeux de données.

random_state (entier, défaut : None)

Graine aléatoire pour la reproductibilité. En recherche et en production, il est fortement recommandé de fixer ce paramètre pour garantir que les résultats soient reproductibles d’une exécution à l’autre. Sans random_state, chaque exécution produira un ensemble différent.


Avantages et limites du Bagging

Avantages

  1. Réduction de variance efficace : Le Bagging réduit significativement la variance sans augmenter le biais, ce qui en fait la méthode idéale pour les modèles instables comme les arbres de décision profonds.
  2. Pas de surapprentissage accru : Contrairement au Boosting, le Bagging ne tend pas à surapprendre même avec un très grand nombre d’estimateurs. Les performances se stabilisent et ne se dégradent pas.
  3. Évaluation intégrée (OOB) : Le score out-of-bag fournit une estimation de la performance généralisée sans nécessiter de validation croisée coûteuse. C’est un avantage pratique considérable.
  4. Parallélisation triviale : Chaque modèle est entraîné indépendamment des autres. Le Bagging se parallélise donc naturellement sur plusieurs processeurs ou machines, ce qui accélère considérablement l’entraînement.
  5. Robustesse au bruit : Comme chaque modèle ne voit qu’un sous-ensemble des données, le bruit présent dans certaines observations a un impact limité sur le résultat final. Les observations bruitées n’apparaissent pas dans tous les échantillons bootstrap.
  6. Simplicité conceptuelle : Le principe est simple à comprendre et à implémenter. Aucune notion de gradient, de poids ou de fonction de perte n’est nécessaire.

Limites

  1. Inefficace pour les modèles stables : Si le modèle de base est déjà stable (faible variance), comme une régression linéaire ou les k-plus proches voisins avec un grand k, le Bagging n’apporte pratiquement aucun bénéfice. Les modèles corrélés ne se diversifient pas suffisamment.
  2. Réduction du biais limitée : Le Bagging ne réduit que la variance, pas le biais. Si le modèle de base est biaisé (sous-apprentissage), le Bagging ne résoudra pas le problème. Dans ce cas, le Boosting (Boosting adaptatif) est plus approprié.
  3. Perte d’interprétabilité : Un ensemble de 100 arbres est beaucoup plus difficile à interpréter qu’un seul arbre. Pour les applications nécessitant de l’explicabilité (santé, finance réglementée), le Bagging peut poser problème.
  4. Coût computationnel : Entraîner 100 modèles est 100 fois plus coûteux qu’en entraîner un seul. Bien que la parallélisation atténue ce problème, les ressources nécessaires restent significatives pour les très grands jeux de données.
  5. Pas de pondération adaptative : Tous les modèles reçoivent le même poids dans le vote final. Les modèles particuliers qui font des erreurs systématiques sur certains sous-espaces ne sont pas corrigés de manière ciblée (contrairement au Boosting qui pondère les observations mal classées).

Quatre cas d’usage concrets du Bagging

Cas 1 : Détection de fraude bancaire

Dans la détection de fraude, les données sont typiquement fortement déséquilibrées (99,9 % de transactions légitimes, 0,1 % de fraude). Un seul arbre de décision tend à ignorer la classe minoritaire. Le Bagging permet de combiner plusieurs arbres, chacun ayant potentiellement capturé des aspects différents des transactions frauduleuses grâce à la diversité des échantillons bootstrap. On peut également combiner le Bagging avec du sous-échantillonnage de la classe majoritaire pour chaque bootstrap, une technique connue sous le nom de Bagged Under Sampling.

Cas 2 : Prédiction du risque médical

En médecine prédictive, la robustesse et la fiabilité sont essentielles. Le Bagging est particulièrement adapté car il produit des prédictions plus stables qu’un modèle unique. Par exemple, pour prédire le risque de réadmission hospitalière d’un patient, un ensemble baggué fournit des prédictions moins sensibles aux particularités d’un échantillon spécifique. Le score out-of-bag offre également une validation intégrée, précieuse quand les jeux de données médicaux sont de taille limitée.

Cas 3 : Évaluation de crédit immobilier

Les institutions financières utilisent massivement les méthodes d’ensemble pour évaluer la solvabilité des emprunteurs. Le Bagging permet de réduire la variance des décisions de crédit, ce qui se traduit par un taux d’erreur plus faible et plus constant. Dans un contexte très régulé, le fait de pouvoir estimer la confiance des prédictions via le score out-of-bag est un avantage réglementaire significatif.

Cas 4 : Maintenance prédictive industrielle

Dans l’industrie 4.0, les capteurs IoT génèrent des flux massifs de données de télémétrie. Le Bagging est idéal pour construire des modèles de prédiction de panne : chaque estimateur peut capturer des patterns de défaillance différents (vibrations anormales, montée en température, usure progressive), et l’agrégation par vote réduit les faux positifs. La parallélisation native du Bagging permet par ailleurs d’entraîner ces modèles sur des clusters distribués, ce qui est indispensable face au volume des données industrielles.


Conclusion

Le Bagging demeure l’une des techniques d’ensemble les plus élégantes et les plus utiles en apprentissage automatique. Son principe fondamental — entraîner de multiples modèles sur des sous-échantillons bootstrap et agréger leurs prédictions — est d’une simplicité remarquable, mais ses implications théoriques sont profondes. En réduisant la variance d’un facteur pouvant atteindre k (le nombre de modèles), le Bagging transforme des modèles instables en prédictions robustes et fiables. Qu’il soit utilisé seul avec un BaggingClassifier ou comme fondation des Random Forests, le Bagging est un outil indispensable dans la boîte à outils de tout praticien du machine learning.

Voir aussi

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.