Prédire si un client va acheter un produit
Si revenus > 50k€
└─ Si âge > 35
└─ Achète (85% de probabilité)
└─ Sinon
└─ N'achète pas (70% de probabilité)
Sinon
└─ N'achète pas (90% de probabilité)
# Créer un dataset de classification
X, y = make_classification(
n_samples=1000,
n_features=20,
n_informative=15,
n_redundant=5,
random_state=42
)
# Séparer train/test
X_train, X_test, y_train, y_test = split_data(X, y, test_size=0.2)
# Créer et entraîner le modèle
tree_model = DecisionTreeClassifier(
max_depth=None, # Pas de limite
min_samples_split=2,
min_samples_leaf=1
)
tree_model.fit(X_train, y_train)
# Évaluation
train_score = tree_model.score(X_train, y_train)
test_score = tree_model.score(X_test, y_test)
# Arbre avec profondeur limitée
tree_constrained = DecisionTreeClassifier(
max_depth=5,
min_samples_split=20,
min_samples_leaf=10
)
tree_constrained.fit(X_train, y_train)
train_score - test_score > 0.1
→ Overfitting probableOn fait varier la taille du training set
train_scores = []
val_scores = []
for size in [100, 200, 500, 1000]:
model.fit(X_train[:size], y_train[:size])
train_scores.append(model.score(X_train[:size], y_train[:size]))
val_scores.append(model.score(X_val, y_val))
plot(train_scores, val_scores)
max_depth
: Limiter la profondeurmin_samples_split
: Minimum pour divisermin_samples_leaf
: Minimum par feuillemax_features
: Limiter les features considéréesCombiner plusieurs arbres de décision pour:
Bootstrap = sampling avec remise
Un sac avec 5 billes numérotées [1,2,3,4,5]. Si tu tires une bille, notes son numéro, la remets, et répètes ça 1000 fois, la moyenne de tous tes tirages sera ~3 (la moyenne originale). C’est exactement ce que fait le bootstrap avec les données.
=> petit scrit python pour illustrer
Dans le bagging classique (comme Random Forest), on utilise des learners qui OVERFITTENT (arbres profonds non contraints), PAS des weak learners avec high bias.
Le bagging peut techniquement améliorer les deux, MAIS :
# Cas 1: OPTIMAL pour bagging - High variance models
tree_overfit = DecisionTreeClassifier(max_depth=None) # ← Random Forest utilise ça!
# Variance: HIGH → bagging très efficace
# Bias: LOW → reste low après bagging
# Cas 2: SOUS-OPTIMAL pour bagging - High bias models
tree_weak = DecisionTreeClassifier(max_depth=2) # ← Weak learner
# Variance: LOW → peu à gagner du bagging
# Bias: HIGH → bagging ne peut pas beaucoup réduire
Pour un ensemble de M modèles :
# Utilise des arbres PROFONDS qui overfittent
RandomForestClassifier(
max_depth=None, # Pas de limite !
min_samples_split=2, # Peut créer des feuilles très spécifiques
min_samples_leaf=1 # Maximum overfit
)
→ Chaque arbre overfit horriblement, mais l’ensemble généralise bien !
# Utilise des WEAK learners avec high bias
AdaBoostClassifier(
base_estimator=DecisionTreeClassifier(max_depth=1), # Stumps!
)
→ Combine séquentiellement des weak learners pour réduire le BIAS
Méthode | Type de base learner | Réduit quoi ? | Exemple |
---|---|---|---|
Bagging | Modèles complexes (overfit) | VARIANCE | Random Forest |
Boosting | Weak learners (underfit) | BIAS | AdaBoost, XGBoost |
Dans votre cours, je recommande de clarifier :
Le bagging est plus efficace avec des modèles instables à haute variance qu’avec des weak learners !
n_estimators
max_features
max_depth
min_samples_split
/ min_samples_leaf
# Charger les données
X, y = load_wine_dataset()
X_train, X_test, y_train, y_test = split_data(X, y)
# Créer le Random Forest
rf_model = RandomForestClassifier(
n_estimators=100,
max_depth=None,
max_features='sqrt',
random_state=42
)
# Entraîner
rf_model.fit(X_train, y_train)
# Évaluer
train_score = rf_model.score(X_train, y_train)
test_score = rf_model.score(X_test, y_test)
max_features_values = [1, 2, 'sqrt', 'log2', None]
results = {}
for mf in max_features_values:
rf = RandomForestClassifier(
n_estimators=100,
max_features=mf
)
rf.fit(X_train, y_train)
results[mf] = {
'train': rf.score(X_train, y_train),
'test': rf.score(X_test, y_test),
'overfit_gap': train - test
}
depths = [2, 5, 10, 20, None]
for depth in depths:
rf = RandomForestClassifier(
n_estimators=100,
max_depth=depth
)
evaluate_model(rf, X_train, X_test, y_train, y_test)
rf = RandomForestClassifier(
n_estimators=100,
oob_score=True
)
rf.fit(X_train, y_train)
print(f"OOB Score: {rf.oob_score_}")
print(f"Test Score: {rf.score(X_test, y_test)}")
rf.fit(X_train, y_train)
importances = rf.feature_importances_
# Visualiser
for feature, importance in zip(feature_names, importances):
print(f"{feature}: {importance:.3f}")
# Top features
top_features = sorted(zip(feature_names, importances),
key=lambda x: x[1],
reverse=True)[:5]
Métrique | Decision Tree | Random Forest |
---|---|---|
Train Accuracy | 100% | 95% |
Test Accuracy | 75% | 88% |
Overfitting Gap | 25% | 7% |
Stabilité | Faible | Élevée |
Temps d’entraînement | Rapide | Plus lent |
Interprétabilité | Excellente | Moyenne |
✅ Simple et interprétable ✅ Pas de preprocessing nécessaire ❌ Tendance forte à l’overfitting ❌ Instable (petits changements → grands impacts)
✅ Réduit significativement l’overfitting ✅ Performance généralement excellente ✅ Robuste et stable ❌ Plus lent et gourmand en ressources ❌ Moins interprétable (boîte noire)
Random Forest a besoin d’arbres qui overfittent (high variance) pour que le bagging fonctionne bien.
# Commencer simple
rf = RandomForestClassifier(n_estimators=100)
# Si plus de temps : optimiser n_estimators et max_features
param_grid = {
'n_estimators': [100, 200, 300],
'max_features': ['sqrt', 0.3, 0.5]
}
Les paramètres par défaut de scikit-learn sont excellents ! Souvent, juste augmenter n_estimators suffit.
https://scikit-learn.org/stable/api/sklearn.tree.html https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html#sklearn.tree.DecisionTreeClassifier https://scikit-learn.org/stable/modules/generated/sklearn.datasets.make_classification.html#sklearn.datasets.make_classification