Analyse exploratoire des données (EDA)
Les bases de l'analyse de données avant modélisation.
Un modèle peut atteindre 80% d'accuracy et être totalement inutile. Découvrez pourquoi le déséquilibre des classes est un piège classique, et comment SMOTE peut (ou ne peut pas) y remédier.
La prédiction du churn (attrition client) est un enjeu majeur pour les entreprises. L'objectif est d'identifier les clients susceptibles de partir, afin de proposer des actions de fidélisation ciblées.
Une entreprise souhaite identifier les clients à risque de churn. Le dataset contient 9 000 clients avec 17 caractéristiques (âge, revenu, comportement d'achat, satisfaction, etc.).

Figure 1 : Le dataset est déséquilibré – seulement 19,7% des clients ont quitté l'entreprise.
Le dataset contient 9 000 clients et 17 caractéristiques :
| Colonne | Type | Description |
|---|---|---|
| Age | numérique | Âge du client (18-69 ans) |
| Gender | catégoriel | Homme, Femme, Autre |
| Annual_Income_USD | numérique | Revenu annuel (20k-150k USD) |
| Spending_Score | numérique | Score de dépense (1-100) |
| Membership_Status | catégoriel | Bronze, Silver, Gold, Platinum |
| Satisfaction_Score | numérique | Score de satisfaction (1-5) |
| Website_Visits_Last_Month | numérique | Visites site web (3-32) |
| Support_Tickets_Last_6_Months | numérique | Tickets support (0-8) |
| Referred_Friends | numérique | Amis parrainés (0-6) |
| Churn | cible | 0 = reste, 1 = quitte |
La matrice de corrélation montre des relations très faibles (entre -0,02 et +0,02). Aucune variable n'est fortement corrélée au churn – c'est un signal d'alarme.
Un modèle peut avoir une accuracy élevée tout en étant totalement inutile. C'est ce qui arrive quand une classe est très majoritaire.
Le Random Forest affiche 80% d'accuracy mais ne détecte aucun client à risque. Le modèle se contente de prédire "reste" pour tout le monde.

Figure 2 : Random Forest – 1 445 vrais restes, 0 churn détecté.
On attribue un poids plus important aux erreurs sur la classe minoritaire.
from sklearn.linear_model import LogisticRegression
lr_model = LogisticRegression(class_weight='balanced', random_state=42)
La Régression Logistique détecte 48% des churn – c'est le meilleur résultat obtenu.
Le Random Forest reste bloqué : la pondération seule ne suffit pas.

Figure 3 : Régression Logistique – 722 restes bien classés, 186 churn détectés (48% de rappel).
SMOTE crée des échantillons synthétiques de la classe minoritaire en interpolant entre les points existants.
from imblearn.over_sampling import SMOTE
smote = SMOTE(random_state=42)
X_train_smote, y_train_smote = smote.fit_resample(X_train, y_train)
print(f"Avant SMOTE : {y_train.value_counts().to_dict()}")
print(f"Après SMOTE : {y_train_smote.value_counts().to_dict()}")
# Résultat : Avant → {0: 5779, 1: 1421} ; Après → {0: 5779, 1: 5779}

Figure 4 : SMOTE crée des points synthétiques entre les voisins de la classe minoritaire.
Amélioration marginale : +0,01 sur le rappel. SMOTE n'apporte pas de gain significatif.
Très faible amélioration : le modèle passe de 0 à 1% de rappel. SMOTE a permis au Random Forest de commencer à apprendre, mais les résultats restent insuffisants.
| Modèle | Équilibrage | Précision (churn) | Rappel (churn) | F1-score (churn) | AUC |
|---|---|---|---|---|---|
| LR | sans | 0,19 | 0,48 | 0,27 | 0,499 |
| LR | class_weight | 0,19 | 0,48 | 0,27 | 0,499 |
| LR + SMOTE | SMOTE | 0,19 | 0,49 | 0,28 | 0,483 |
| RF | sans | 0,00 | 0,00 | 0,00 | 0,508 |
| RF + class_weight | class_weight | 0,00 | 0,00 | 0,00 | 0,508 |
| RF + SMOTE | SMOTE | 0,25 | 0,01 | 0,02 | 0,513 |
La matrice montre que SMOTE a légèrement modifié la répartition, mais sans gain significatif.
SMOTE a permis au Random Forest de détecter 3 churn sur 355 (soit 0,8%). C'est très faible, mais c'est mieux que 0.

Figure 5 : Les 4 matrices de confusion – la Régression Logistique donne les meilleurs résultats.
Même avec des techniques avancées comme SMOTE, un modèle ne peut pas apprendre si les données d'entrée ne contiennent pas d'information discriminante. Ici, les features disponibles (âge, revenu, satisfaction, etc.) ne suffisent pas à distinguer les clients qui partent de ceux qui restent.
scale_pos_weightLe Random Forest est un modèle complexe qui a besoin de beaucoup de signal pour apprendre. Ici, les features sont peu discriminantes (corrélations proches de 0). SMOTE crée des points synthétiques à partir de ces données peu séparées, donc les nouveaux points ne sont pas plus discriminants. La Régression Logistique, plus simple, a mieux résisté.
Le rappel (recall) est la métrique la plus importante : il mesure la proportion de churn réels que le modèle a détectés. Un faux négatif (client qui part non détecté) est coûteux. La précision est moins critique (quelques faux positifs sont acceptables).
SMOTE est utile quand les données sont déjà raisonnablement séparables. Si les classes se chevauchent beaucoup (overlap important), SMOTE ne crée pas de nouveaux points réellement informatifs. Dans notre cas, l'overlap est trop important.
1) Collecter plus de features (historique des interactions, données de navigation)
2) Utiliser l'ingénierie de features (créer des ratios, des tendances)
3) Essayer XGBoost avec scale_pos_weight
4) Utiliser des méthodes d'échantillonnage combinées (SMOTE + undersampling)
5) Changer d'approche : passer en apprentissage non supervisé pour détecter les anomalies
class_weight modifie la fonction de coût du modèle (erreurs sur la classe minoritaire sont plus pénalisées). SMOTE modifie le dataset d'entraînement (ajoute des points synthétiques). Les deux peuvent être combinés, mais ne résolvent pas un manque de signal.