Une régression faite pour les comptages : nombre de sinistres, de visites, de pannes, d'appels. Elle prévoit un taux d'événements toujours positif, et chaque variable agit comme un multiplicateur. Avec l'exposition, elle compare équitablement un client suivi six mois et un client suivi un an.
Un tarif par multiplicateurs : une fréquence de base, × 3 si jeune conducteur, × 1,3 en ville. C'est exactement la forme du modèle.
Le log du nombre attendu d'événements est une somme pondérée des variables. Le passage au log garantit une prévision positive et transforme les effets en multiplicateurs.
Un contrat couvert 6 mois a deux fois moins d'occasions de sinistre qu'un contrat d'un an. On l'intègre en « offset » : le modèle prévoit un taux par an.
L'algorithme cherche les poids qui rendent les comptages observés les plus probables, sous l'hypothèse d'une loi de Poisson.
Âge du conducteur, puissance du véhicule, coefficient bonus-malus, zone, durée couverte dans l'année (exposition). Et le nombre de sinistres déclarés : 0 pour la grande majorité, parfois 1, 2 ou 3.
Sur le jeu d'exemple, un conducteur de moins de 25 ans a une fréquence environ 3 fois plus élevée, la zone urbaine multiplie par 1,3 et la zone rurale par 0,86 par rapport au périurbain. Chaque cheval fiscal ajoute environ 6 %.
Sur les contrats jamais vus, le modèle prévoit 127 sinistres pour 137 observés. On compare aussi par segment (âge, zone) : c'est là qu'un tarif mal calibré coûte cher. La déviance de Poisson sert à comparer deux modèles.
Noms donnés pour R (glm) et Python (scikit-learn).
En R, l'exposition entre en offset. scikit-learn n'a pas d'offset : on modélise le taux nb_sinistres / exposition avec sample_weight = exposition, ce qui revient au même pour la loi de Poisson.
PoissonRegressor applique par défaut une pénalité Ridge (alpha = 1). Pour un modèle identique à glm(), il faut alpha = 0.
On divise la somme des résidus de Pearson au carré par les degrés de liberté. Nettement au-dessus de 1, les erreurs standard sont trop optimistes : family = quasipoisson ou MASS::glm.nb.
L'effet de l'âge n'est pas linéaire. On crée des tranches (moins de 25 ans, 25-60, plus de 60) ou on passe à un GAM.
# Fréquence des sinistres auto : régression de Poisson en R
sinistres <- read.csv("sinistres.csv")
sinistres$jeune <- as.numeric(sinistres$age_conducteur < 25)
sinistres$zone <- factor(sinistres$zone) # référence : periurbain
set.seed(42)
idx <- sample(nrow(sinistres), round(0.7 * nrow(sinistres)))
train <- sinistres[idx, ]
test <- sinistres[-idx, ]
# offset(log(exposition)) : un contrat couvert 6 mois a deux fois moins de chances de sinistre
modele <- glm(nb_sinistres ~ jeune + puissance_cv + bonus_malus + zone + offset(log(exposition)),
family = poisson, data = train)
# Rapports de fréquence : effet multiplicatif de chaque variable
print(round(exp(coef(modele))[-1], 2))
# Surdispersion : proche de 1 attendu, bien au-dessus => quasi-Poisson ou binomiale négative
cat("Dispersion :", round(sum(residuals(modele, type = "pearson")^2) / modele$df.residual, 2), "\n")
# Contrôle sur les contrats jamais vus : sinistres prévus vs observés
prevus <- predict(modele, newdata = test, type = "response")
cat("Sinistres observés :", sum(test$nb_sinistres), "| prévus :", round(sum(prevus), 1), "\n")
# Fréquence des sinistres auto : régression de Poisson en Python
import numpy as np
import pandas as pd
from sklearn.linear_model import PoissonRegressor
from sklearn.model_selection import train_test_split
sinistres = pd.read_csv("sinistres.csv")
sinistres["jeune"] = (sinistres["age_conducteur"] < 25).astype(float)
X = pd.get_dummies(sinistres[["jeune", "puissance_cv", "bonus_malus", "zone"]], drop_first=True, dtype=float)
train, test, X_train, X_test = train_test_split(sinistres, X, test_size=0.3, random_state=42)
# Exposition : on modélise le taux par an, pondéré par la durée couverte
modele = PoissonRegressor(alpha=0, max_iter=1000)
modele.fit(X_train, train["nb_sinistres"] / train["exposition"], sample_weight=train["exposition"])
# Rapports de fréquence : effet multiplicatif de chaque variable
print(pd.Series(np.exp(modele.coef_), index=X.columns).round(2))
# Contrôle sur les contrats jamais vus : sinistres prévus vs observés
prevus = modele.predict(X_test) * test["exposition"]
print("Sinistres observés :", test["nb_sinistres"].sum(), "| prévus :", round(prevus.sum(), 1))
Quand la cible est un nombre d'événements, entier et positif, avec beaucoup de zéros. Une régression linéaire peut prévoir des valeurs négatives et suppose une variance constante, alors qu'un comptage varie davantage quand sa moyenne augmente.
L'offset tient compte de la durée ou de la taille d'exposition. Avec offset(log(exposition)), le modèle prévoit un taux par unité d'exposition, par exemple par an, et un contrat suivi six mois n'est pas comparé à tort à un contrat suivi un an.
On prend son exponentielle : c'est un rapport de taux. Un coefficient exponentié de 1,3 pour la zone urbaine signifie une fréquence multipliée par 1,3 par rapport à la zone de référence, les autres variables restant égales.
Poisson est un GLM parmi d'autres. En tarification, on l'associe à un GLM Gamma pour le coût.
Voir la fiche → quand l'âge courbeRemplace les tranches par des courbes lisses, avec la même loi de Poisson.
Voir la fiche → souvent plus précisAvec une perte de Poisson, il capte seul les interactions, 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