Cas pratique · Machine Learning · Churn prediction

Prédiction du churn client avec Python – Déséquilibre des classes et limites du Machine Learning

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.

Niveau : intermédiaire | Temps de lecture : 15 min | Outil : Python (scikit-learn, imbalanced-learn)

1. Contexte et objectif

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.

Problématique métier

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.).

19,7%
taux de churn dans le dataset
1 776 clients sur 9 000
80,3%
clients restants
7 224 clients

Distribution du churn : 80,3% reste, 19,7% quitte

Figure 1 : Le dataset est déséquilibré – seulement 19,7% des clients ont quitté l'entreprise.

2. Présentation du dataset

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
Corrélation avec le churn

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.

3. Premier modèle (sans équilibrage) – des résultats trompeurs

 Le piège classique

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.

Régression Logistique (sans équilibrage)

0,19
Précision (churn)
0,48
Rappel (churn)
0,27
F1-score (churn)

Random Forest (sans équilibrage)

0,00
Précision (churn)
0,00
Rappel (churn)
0,00
F1-score (churn)

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.

Matrice de confusion Random Forest sans équilibrage

Figure 2 : Random Forest – 1 445 vrais restes, 0 churn détecté.

4. Pondération des classes (class_weight='balanced')

On attribue un poids plus important aux erreurs sur la classe minoritaire.

class_weight='balanced'
from sklearn.linear_model import LogisticRegression

lr_model = LogisticRegression(class_weight='balanced', random_state=42)

Régression Logistique (avec class_weight)

0,19
Précision (churn)
0,48
Rappel (churn)
0,27
F1-score (churn)

La Régression Logistique détecte 48% des churn – c'est le meilleur résultat obtenu.

Random Forest (avec class_weight)

0,00
Précision (churn)
0,00
Rappel (churn)
0,00
F1-score (churn)

Le Random Forest reste bloqué : la pondération seule ne suffit pas.

Matrice de confusion Régression Logistique avec class_weight

Figure 3 : Régression Logistique – 722 restes bien classés, 186 churn détectés (48% de rappel).

5. SMOTE : synthétiser des données pour équilibrer

SMOTE (Synthetic Minority Over-sampling Technique)

SMOTE crée des échantillons synthétiques de la classe minoritaire en interpolant entre les points existants.

SMOTE avec imbalanced-learn
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}

Schéma du fonctionnement de SMOTE

Figure 4 : SMOTE crée des points synthétiques entre les voisins de la classe minoritaire.

Régression Logistique + SMOTE

0,19
Précision (churn)
0,49
Rappel (churn)
0,28
F1-score (churn)

Amélioration marginale : +0,01 sur le rappel. SMOTE n'apporte pas de gain significatif.

Random Forest + SMOTE

0,25
Précision (churn)
0,01
Rappel (churn)
0,02
F1-score (churn)

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.

6. Comparaison des 4 modèles

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
Le meilleur résultat : Régression Logistique avec class_weight – 48% de rappel sur les churn.

7. Analyse des matrices de confusion

Régression Logistique (avant vs après SMOTE)

722 / 723
Reste bien classés (avant)
718 / 727
Reste bien classés (après)

La matrice montre que SMOTE a légèrement modifié la répartition, mais sans gain significatif.

Random Forest (avant vs après SMOTE)

0 / 0
Churn détectés (avant)
0%
3 / 352
Churn détectés (après)
~1%

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.

Comparaison des 4 matrices de confusion

Figure 5 : Les 4 matrices de confusion – la Régression Logistique donne les meilleurs résultats.

8. Conclusion : quand l'équilibrage ne suffit pas

 Leçon principale

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.

À retenir

  • L'accuracy est trompeuse sur des datasets déséquilibrés
  • class_weight='balanced' améliore la Régression Logistique (48% de rappel)
  • SMOTE n'a pas apporté de gain significatif (car les features sont peu discriminantes)
  • Random Forest a du mal sur ce type de données (trop complexe pour peu de signal)
  • Le meilleur modèle reste la Régression Logistique avec class_weight
  • Pour améliorer les résultats : collecter plus de features, enrichir les données, ou changer d'approche
Recommandations pour aller plus loin :
  • Collecter des données comportementales plus fines (fréquence de connexion, interactions support, etc.)
  • Utiliser des modèles à base d'arbres avec échantillonnage (Balanced Random Forest)
  • Explorer le XGBoost avec paramètre scale_pos_weight
  • Changer de métrique : optimiser directement le rappel ou le F1-score

9. FAQ — Déséquilibre des classes et churn prediction

Pourquoi le Random Forest a-t-il échoué même avec SMOTE ?

Le 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é.

Quelle métrique prioriser pour le churn prediction ?

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-il toujours utile ?

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.

Comment améliorer les résultats ?

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

Quelle est la différence entre class_weight et SMOTE ?

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.

 

Recevez la veille IA & Data qui compte vraiment

 

    Analyses claires, outils concrets et tendances IA sans bruit.     Rejoignez les lecteurs de IANA Data.