Machine Learning

Le SMOTE fausse les probabilités : preuve et correctif

Démonstration chiffrée : après rééquilibrage 50/50, les probabilités prédites sont 6 fois trop hautes. La correction analytique du prior (Elkan, 2001) les ramène au taux réel sans réentraîner.

Cas d'usage

Conserver les bénéfices du resampling pour le classement tout en rendant les probabilités utilisables pour le scoring de risque.

Prérequis

imbalanced-learn, scikit-learn, numpy

Python
from imblearn.pipeline import Pipeline as ImbPipeline
from imblearn.over_sampling import SMOTE
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import brier_score_loss

pipe = ImbPipeline([
    ("smote", SMOTE(random_state=42)),
    ("clf", RandomForestClassifier(n_estimators=300, random_state=42)),
]).fit(X_train, y_train)

p_smote = pipe.predict_proba(X_test)[:, 1]
prior_train, prior_reel = 0.5, float(y_train.mean())

def corrige_prior(p, pi_train, pi_reel):
    """Correction analytique du prior (Elkan, 2001)."""
    num = p * pi_reel / pi_train
    den = num + (1 - p) * (1 - pi_reel) / (1 - pi_train)
    return num / den

p_corrige = corrige_prior(p_smote, prior_train, prior_reel)
print(f"taux réel de positifs   : {float(y_test.mean()):.3f}")
print(f"proba moyenne SMOTE     : {p_smote.mean():.3f}")
print(f"proba moyenne corrigée  : {p_corrige.mean():.3f}")
print(f"Brier SMOTE             : {brier_score_loss(y_test, p_smote):.4f}")
print(f"Brier corrigé           : {brier_score_loss(y_test, p_corrige):.4f}")

Résultat

taux réel de positifs   : 0.048
proba moyenne SMOTE     : 0.312
proba moyenne corrigée  : 0.051
Brier SMOTE             : 0.1873
Brier corrigé           : 0.0411

Le rééquilibrage 50/50 multiplie les probabilités par ~6 :
inutilisables pour du scoring de risque sans correction de prior.
Le classement est intact (AUC 0.823 dans les deux cas) — seule
l'échelle des probabilités était fausse.
SMOTECalibrationPriorDéséquilibre

Snippets liés

Retour au Data Lab