Une scorecard est une grille de points : chaque tranche de chaque variable rapporte ou coûte des points, et le total classe le dossier. Derrière, une régression logistique sur des variables découpées en tranches. C'est le format standard du risque de crédit, repris en assurance, parce qu'il se lit, se contrôle et s'applique sans ordinateur.
Un barème de permis à points inversé : jeune conducteur, moins de points ; bon historique, plus de points. On additionne, on compare à un seuil.
Âge en 3 tranches, bonus-malus en 3 tranches… Chaque tranche doit contenir assez de dossiers et avoir un taux de risque cohérent avec le métier.
Le modèle estime l'effet de chaque tranche sur la cote de risque, toutes choses égales par ailleurs. En banque, on code souvent les tranches par leur Weight of Evidence (WoE).
On fixe une convention, par exemple 20 points de plus pour une cote de risque divisée par deux (PDO). Chaque coefficient devient un nombre entier de points.
Âge du conducteur, puissance du véhicule, zone, coefficient bonus-malus et durée d'observation du contrat. Et la cible : le contrat a-t-il eu au moins un sinistre ?
Sur le jeu d'exemple, par rapport à un conducteur de 18 à 24 ans, un conducteur de 25 ans ou plus gagne environ 33 points ; un bonus-malus d'au moins 1,2 en coûte 14 ; un véhicule de 9 CV ou plus en coûte 10.
L'AUC (0,68 ici) dit si la grille classe bien les sinistrés. En banque, on suit aussi le Gini (2 × AUC - 1) et la stabilité de la population d'une année sur l'autre (PSI), pour savoir quand refaire la grille.
La qualité d'une scorecard se joue dans le découpage. En R, le package scorecard automatise tranches et WoE ; en Python, optbinning.
Assez de dossiers par tranche (souvent au moins 5 %), un taux de risque qui évolue dans un sens logique, des seuils parlants pour le métier.
Les indicatrices donnent un coefficient par tranche, comme ici. Le WoE résume chaque tranche par un seul chiffre de risque : un coefficient par variable, et une grille plus stable.
Le nombre de points qui double la cote (PDO, ici 20) et le score associé à une cote de référence. Pure convention, mais à fixer une fois pour toutes.
On garde les variables au pouvoir prédictif suffisant, mesuré par l'Information Value (IV), et peu corrélées entre elles.
# Score de risque auto à la souscription : scorecard en R
contrats <- read.csv("sinistres.csv")
contrats$sinistre <- as.integer(contrats$nb_sinistres > 0)
# 1. Chaque variable découpée en tranches (la 1re tranche sert de référence)
contrats$age <- cut(contrats$age_conducteur, c(18, 25, 35, 100), right = FALSE)
contrats$puissance <- cut(contrats$puissance_cv, c(0, 9, 20), right = FALSE)
contrats$bonus_malus <- cut(contrats$bonus_malus, c(0, 1, 1.2, 2), right = FALSE)
contrats$zone <- factor(contrats$zone)
set.seed(42)
idx <- sample(nrow(contrats), round(0.7 * nrow(contrats)))
# 2. Régression logistique ; log(exposition) ajuste la durée observée, hors grille
modele <- glm(sinistre ~ age + puissance + bonus_malus + zone + log(exposition),
data = contrats[idx, ], family = binomial)
# 3. Conversion en points : 20 points de plus = cote de sinistre divisée par 2
facteur <- 20 / log(2)
coefs <- coef(modele)[-1]
coefs <- coefs[names(coefs) != "log(exposition)"]
print(round(-coefs * facteur))
# AUC test (formule des rangs) : le score classe-t-il bien les sinistrés ?
proba <- predict(modele, contrats[-idx, ], type = "response")
reel <- contrats$sinistre[-idx]
n1 <- sum(reel == 1)
cat("AUC test :", round((sum(rank(proba)[reel == 1]) - n1 * (n1 + 1) / 2) / (n1 * sum(reel == 0)), 3), "\n")
# Score de risque auto à la souscription : scorecard en Python
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
contrats = pd.read_csv("sinistres.csv")
y = (contrats["nb_sinistres"] > 0).astype(int)
# 1. Chaque variable découpée en tranches (la 1re tranche sert de référence)
tranches = pd.DataFrame({
"age": pd.cut(contrats["age_conducteur"], [18, 25, 35, 100], right=False),
"puissance": pd.cut(contrats["puissance_cv"], [0, 9, 20], right=False),
"bonus_malus": pd.cut(contrats["bonus_malus"], [0, 1, 1.2, 2], right=False),
"zone": contrats["zone"]})
X = pd.get_dummies(tranches.astype(str), drop_first=True, dtype=float)
X["log_exposition"] = np.log(contrats["exposition"]) # durée observée : ajustement, hors grille
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)
# 2. Régression logistique sur les tranches (C élevé : quasiment sans pénalité)
modele = LogisticRegression(C=1e6, max_iter=1000).fit(X_train, y_train)
print("AUC test :", round(roc_auc_score(y_test, modele.predict_proba(X_test)[:, 1]), 3))
# 3. Conversion en points : 20 points de plus = cote de sinistre divisée par 2
facteur = 20 / np.log(2)
points = -modele.coef_[0][:-1] * facteur
print(pd.Series(points, index=X.columns[:-1]).round().astype(int))
On découpe chaque variable en tranches, on ajuste une régression logistique sur ces tranches, puis on convertit les coefficients en points selon une échelle fixée à l'avance. Le score d'un dossier est la somme des points de ses tranches.
C'est une mesure du risque de chaque tranche : le logarithme du rapport entre la part des bons dossiers et la part des mauvais dossiers dans cette tranche. Coder les tranches par leur WoE rend la relation avec le risque monotone et facilite la conversion en points.
Points to Double the Odds : le nombre de points qui correspond à une cote doublée. Avec un PDO de 20, un dossier qui a 20 points de plus a une cote de risque deux fois plus faible (ou de bonne issue deux fois plus forte, selon la convention).
La scorecard est une régression logistique présentée en points.
Voir la fiche → le challengerSouvent plus discriminant. Sert de modèle de comparaison pour mesurer ce que la grille laisse sur la table.
Voir la fiche → pour expliquer un modèle complexeSi l'on remplace la grille par un modèle plus fort, SHAP permet d'en justifier chaque score.
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