Un modèle qui explique le temps avant un événement : départ d'un client, panne, résiliation. Il tient compte des clients encore présents, dont on ne connaît pas encore la date de départ. Chaque variable reçoit un hazard ratio, qui dit par combien elle multiplie le risque de partir à tout moment.
Un compte à rebours propre à chaque client, qui tourne plus ou moins vite. Le modèle ne décrit pas le compte à rebours de base : il mesure seulement ce qui l'accélère ou le ralentit.
Pour chaque client : depuis combien de mois il est là, et s'il est parti. Un client encore présent est « censuré » : on sait seulement qu'il a tenu au moins jusqu'ici.
À chaque départ, le modèle compare le client parti à tous ceux encore présents à cette ancienneté. Les variables qui distinguent les partants reçoivent un poids.
Le risque de base, qui varie avec le temps, n'est pas modélisé. Chaque variable le multiplie par un facteur constant : le hazard ratio.
Pour chaque client : ancienneté en mois, départ ou non, appels au support, incidents récents, montant mensuel, type de contrat. Les clients toujours là ne sont pas écartés : ils comptent jusqu'à leur ancienneté actuelle.
Sur le jeu d'exemple, chaque appel au support multiplie le risque de départ par 1,3, chaque incident par 1,26. Un contrat mensuel le multiplie par 1,7 par rapport à un contrat annuel, un contrat deux ans le divise par près de 2.
L'indice de concordance mesure si les clients partis plus tôt avaient bien un risque plus élevé : 0,5 correspond au hasard, 1 à la perfection. On vérifie aussi que chaque effet reste stable dans le temps (test des résidus de Schoenfeld).
Noms donnés pour R (survival) et Python (lifelines).
La définition de la durée et de l'événement fait tout le modèle. Un client parti vaut 1, un client présent vaut 0 et sa durée est son ancienneté actuelle.
Le test des risques proportionnels. Une p-value faible sur une variable signale un effet qui varie dans le temps : on stratifie sur cette variable (strata) ou on la fait dépendre du temps.
Avec une durée en mois, beaucoup de clients partent au même moment. La méthode d'Efron, par défaut en R comme dans lifelines, les gère correctement.
lifelines peut pénaliser les coefficients, comme Ridge ou Lasso. Utile avec beaucoup de variables ; à laisser à 0 pour retrouver les résultats de R.
# Moteurs du départ client : modèle de Cox en R
library(survival)
clients <- read.csv("clients_churn.csv")
clients$contrat <- factor(clients$contrat) # référence : annuel
# Durée = ancienneté en mois, événement = départ (churn = 1), sinon client toujours là
modele <- coxph(Surv(anciennete, churn) ~ appels_support + incidents_3m + montant + contrat,
data = clients)
# Hazard ratios et intervalles à 95 % : effet multiplicatif sur le risque instantané de départ
print(round(summary(modele)$conf.int[, c("exp(coef)", "lower .95", "upper .95")], 3))
cat("Indice de concordance :", round(summary(modele)$concordance[1], 3), "\n")
# Hypothèse des risques proportionnels : une p-value faible signale un effet qui varie dans le temps
print(cox.zph(modele))
# Part de clients encore là à 12 et 24 mois, pour deux profils
profils <- data.frame(appels_support = c(0, 4), incidents_3m = c(0, 2), montant = 45,
contrat = factor(c("deux_ans", "mensuel"), levels = levels(clients$contrat)))
print(summary(survfit(modele, newdata = profils), times = c(12, 24)))
# Moteurs du départ client : modèle de Cox en Python
import pandas as pd
from lifelines import CoxPHFitter
clients = pd.read_csv("clients_churn.csv")
# Durée = ancienneté en mois, événement = départ (churn = 1), sinon client toujours là
donnees = pd.get_dummies(clients[["anciennete", "churn", "appels_support", "incidents_3m", "montant", "contrat"]],
columns=["contrat"], drop_first=True, dtype=float) # référence : annuel
cph = CoxPHFitter()
cph.fit(donnees, duration_col="anciennete", event_col="churn")
# Hazard ratios : effet multiplicatif sur le risque instantané de départ
print(cph.hazard_ratios_.round(3))
print("Indice de concordance :", round(cph.concordance_index_, 3))
# Hypothèse des risques proportionnels (tests et conseils affichés)
cph.check_assumptions(donnees, p_value_threshold=0.05)
# Part de clients encore là à 12 et 24 mois, pour deux profils
profils = pd.DataFrame({"appels_support": [0, 4], "incidents_3m": [0, 2], "montant": [45, 45],
"contrat_deux_ans": [1.0, 0.0], "contrat_mensuel": [0.0, 1.0]})
print(cph.predict_survival_function(profils, times=[12, 24]).round(3))
Un hazard ratio de 1,3 pour les appels au support signifie qu'à tout moment, chaque appel supplémentaire multiplie par 1,3 le risque instantané de départ, les autres variables étant égales. Au-dessus de 1, le départ est accéléré ; en dessous, il est retardé.
Un individu est censuré quand l'événement ne s'est pas encore produit à la fin de l'observation : un client toujours abonné, une machine qui fonctionne encore. On sait seulement que sa durée dépasse la durée observée. Les modèles de survie utilisent cette information au lieu d'écarter ces individus.
Le modèle de Cox suppose que chaque variable multiplie le risque par un facteur constant dans le temps. Si un contrat deux ans protège fortement la première année puis plus du tout, l'hypothèse est violée. On le teste avec les résidus de Schoenfeld (cox.zph en R).
Décrit la part de clients restants au fil du temps, sans variable explicative. À tracer avant le Cox.
Voir la fiche → à horizon fixePrévoit un départ oui / non à une date donnée. Plus simple, mais perd l'information sur les clients récents.
Voir la fiche → en version survieLes forêts aléatoires de survie captent les effets non linéaires, au prix de la lisibilité.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus