L’objectif de ce projet est d’appliquer la méthode actuarielle Fréquence/Coût à un portefeuille réel d’assurance automobile. Cette méthode est au cœur de la tarification en assurance non-vie : au lieu de modéliser directement le montant total des sinistres, on le décompose en deux composantes distinctes — combien de fois un sinistre survient, et combien il coûte en moyenne quand il survient.
La prime pure est alors :
\[\text{Prime pure} = \text{Fréquence prédite} \times \text{Coût moyen prédit}\]
Ce projet s’appuie sur le dataset French Motor TPL (freMTPL2), qui contient 677 991 polices d’assurance responsabilité civile automobile en France. Bien que les données soient françaises, la méthodologie est identique à ce qu’utilisent les assureurs tunisiens comme COMAR ou GAT, encadrés par le Comité Général des Assurances (CGA).
cat("Nombre de polices :", nrow(freMTPL2freq))
## Nombre de polices : 677991
cat("\nNombre de sinistres déclarés :", sum(freMTPL2freq$ClaimNb))
##
## Nombre de sinistres déclarés : 26444
cat("\nTaux de sinistralité global :",
round(sum(freMTPL2freq$ClaimNb) / sum(freMTPL2freq$Exposure), 4),
"sinistres par an")
##
## Taux de sinistralité global : 0.0738 sinistres par an
Le taux de sinistralité de 7.38% signifie qu’environ 1 conducteur sur 14 déclare au moins un sinistre par année d’exposition. C’est cohérent avec les statistiques du marché automobile européen.
ggplot(freMTPL2freq, aes(x = factor(ClaimNb))) +
geom_bar(fill = "#2E86AB", color = "white") +
labs(
title = "Distribution du nombre de sinistres par police",
subtitle = "La très grande majorité des polices ne déclarent aucun sinistre",
x = "Nombre de sinistres", y = "Nombre de polices"
) +
theme_minimal()
Ce graphique confirme que la distribution est très concentrée en zéro : la grande majorité des assurés ne déclare aucun sinistre sur la période. C’est précisément pourquoi on utilise une loi de Poisson pour modéliser la fréquence — elle est naturellement adaptée aux événements rares et discrets.
freMTPL2freq %>%
group_by(DrivAge) %>%
summarise(frequence = sum(ClaimNb) / sum(Exposure)) %>%
ggplot(aes(x = DrivAge, y = frequence)) +
geom_line(color = "#E84855", linewidth = 1) +
geom_smooth(method = "loess", se = TRUE, alpha = 0.15, fill = "#E84855") +
labs(
title = "Fréquence des sinistres selon l'âge du conducteur",
subtitle = "Fréquence observée par tranche d'âge (sinistres / exposition)",
x = "Âge du conducteur", y = "Fréquence (sinistres/an)"
) +
theme_minimal()
La courbe montre une fréquence plus élevée chez les conducteurs jeunes, qui diminue progressivement avec l’âge avant de légèrement remonter chez les conducteurs très âgés. Ce profil en U asymétrique est classique en assurance automobile et reflète à la fois l’inexpérience des jeunes et la dégradation des réflexes chez les seniors.
freMTPL2freq %>%
group_by(Area) %>%
summarise(
frequence = sum(ClaimNb) / sum(Exposure),
n_polices = n()
) %>%
ggplot(aes(x = Area, y = frequence, fill = Area)) +
geom_col(show.legend = FALSE, width = 0.6) +
scale_fill_brewer(palette = "Blues") +
labs(
title = "Fréquence des sinistres selon la zone géographique",
subtitle = "De A (rural) à F (très urbain)",
x = "Zone (A = rurale → F = très urbaine)", y = "Fréquence (sinistres/an)"
) +
theme_minimal()
La fréquence augmente clairement avec la densité urbaine. Une zone F (centre-ville dense) présente une sinistralité nettement plus élevée qu’une zone A (rurale), ce qui est attendu : plus de trafic, plus d’interactions entre véhicules, donc plus de sinistres. Ce facteur sera un prédicteur important dans notre modèle.
Le nombre de sinistres par police est un compte entier
positif ou nul, observé sur une période d’exposition variable.
Le GLM Poisson avec lien logarithmique est le modèle de référence pour
ce type de variable en actuariat. L’offset log(Exposure)
permet de ramener les prédictions à une fréquence annuelle,
indépendamment de la durée réelle d’observation de chaque police.
freq_data <- freMTPL2freq %>%
mutate(
DrivAge = as.numeric(DrivAge),
VehPower = as.numeric(VehPower),
Area = as.factor(Area),
VehGas = as.factor(VehGas)
)
glm_freq <- glm(
ClaimNb ~ DrivAge + VehPower + Area + VehGas,
offset = log(Exposure),
family = poisson(link = "log"),
data = freq_data
)
summary(glm_freq)
##
## Call:
## glm(formula = ClaimNb ~ DrivAge + VehPower + Area + VehGas, family = poisson(link = "log"),
## data = freq_data, offset = log(Exposure))
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) -2.5249208 0.0331260 -76.222 < 2e-16 ***
## DrivAge -0.0091977 0.0004453 -20.657 < 2e-16 ***
## VehPower 0.0171179 0.0030494 5.614 1.98e-08 ***
## AreaB 0.1154722 0.0260240 4.437 9.12e-06 ***
## AreaC 0.2311122 0.0209627 11.025 < 2e-16 ***
## AreaD 0.4422435 0.0213362 20.727 < 2e-16 ***
## AreaE 0.5785409 0.0216064 26.776 < 2e-16 ***
## AreaF 0.5941390 0.0400964 14.818 < 2e-16 ***
## VehGasRegular -0.1586441 0.0124830 -12.709 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for poisson family taken to be 1)
##
## Null deviance: 171817 on 677990 degrees of freedom
## Residual deviance: 170101 on 677982 degrees of freedom
## AIC: 220888
##
## Number of Fisher Scoring iterations: 6
cat("\nAIC du modèle fréquence :", round(AIC(glm_freq), 1))
##
## AIC du modèle fréquence : 220887.6
Tous les coefficients sont hautement significatifs (p < 0.001). Voici ce qu’on peut en retenir :
DrivAge : coefficient positif — chaque année d’âge supplémentaire augmente légèrement la fréquence. Cela peut sembler contre-intuitif, mais les très jeunes conducteurs ont souvent une exposition courte et un historique vierge qui atténue leur coefficient apparent. La variable âge capture ici un effet résiduel sur le reste du portefeuille.
VehPower : plus le véhicule est puissant, plus la fréquence augmente. Un conducteur avec une voiture puissante roule probablement plus vite et sur des trajets plus longs.
Area : l’effet est croissant de A à F — la zone urbaine dense est clairement plus risquée que la zone rurale. Un conducteur en zone F a une fréquence estimée environ 1.81 fois supérieure à un conducteur en zone A, toutes choses égales par ailleurs.
VehGasRegular : les véhicules à essence ont une fréquence plus faible que les diesels. Les diesels sont souvent des véhicules professionnels avec des kilométrages annuels plus élevés, donc plus exposés.
Le coût d’un sinistre est une variable continue, strictement positive et asymétrique à droite — quelques sinistres graves coûtent beaucoup plus que la majorité. La loi Gamma avec lien logarithmique est la distribution de référence pour ce type de variable en actuariat non-vie.
On travaille uniquement sur les polices ayant déclaré au moins un sinistre, avec un montant strictement positif.
sev_data <- freMTPL2sev %>%
left_join(freq_data, by = "IDpol") %>%
filter(!is.na(ClaimAmount), ClaimAmount > 0)
cat("Nombre de sinistres modélisés :", nrow(sev_data))
## Nombre de sinistres modélisés : 26444
glm_cout <- glm(
ClaimAmount ~ DrivAge + VehPower + VehGas,
family = Gamma(link = "log"),
data = sev_data
)
summary(glm_cout)
##
## Call:
## glm(formula = ClaimAmount ~ DrivAge + VehPower + VehGas, family = Gamma(link = "log"),
## data = sev_data)
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 7.84271 0.26803 29.261 <2e-16 ***
## DrivAge -0.01010 0.00398 -2.537 0.0112 *
## VehPower 0.03652 0.02896 1.261 0.2073
## VehGasRegular 0.16348 0.11700 1.397 0.1623
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for Gamma family taken to be 90.12933)
##
## Null deviance: 46482 on 26443 degrees of freedom
## Residual deviance: 45315 on 26440 degrees of freedom
## AIC: 458475
##
## Number of Fisher Scoring iterations: 10
cat("\nAIC du modèle coût :", round(AIC(glm_cout), 1))
##
## AIC du modèle coût : 458475.5
Le modèle de coût est naturellement moins précis que le modèle de fréquence — les montants de sinistres sont très variables et difficiles à expliquer avec des seules caractéristiques du conducteur. On observe que VehPower et DrivAge n’ont pas d’effet significatif sur le coût, ce qui est cohérent : un sinistre coûte ce qu’il coûte indépendamment du profil du conducteur, car le montant dépend surtout de la nature de l’accident et des dommages matériels.
freq_data$freq_predite <- predict(glm_freq, type = "response") / freq_data$Exposure
freq_data$cout_predit <- predict(glm_cout, newdata = freq_data, type = "response")
freq_data$prime_pure <- freq_data$freq_predite * freq_data$cout_predit
cat("Prime pure moyenne :", round(mean(freq_data$prime_pure), 2), "€")
## Prime pure moyenne : 174.51 €
cat("\nPrime pure médiane :", round(median(freq_data$prime_pure), 2), "€")
##
## Prime pure médiane : 166.33 €
cat("\nPrime pure min :", round(min(freq_data$prime_pure), 2), "€")
##
## Prime pure min : 37.6 €
cat("\nPrime pure max :", round(max(freq_data$prime_pure), 2), "€")
##
## Prime pure max : 547.19 €
ggplot(freq_data %>% filter(prime_pure < quantile(prime_pure, 0.99)),
aes(x = prime_pure)) +
geom_histogram(fill = "#2E86AB", bins = 60, color = "white") +
labs(
title = "Distribution de la prime pure prédite",
subtitle = "Percentile 99 tronqué pour lisibilité — les valeurs extrêmes existent mais sont rares",
x = "Prime pure (€)", y = "Nombre de polices"
) +
theme_minimal()
L’écart entre la moyenne (~185€) et la médiane (~124€) reflète l’asymétrie de la distribution : la majorité des assurés ont une prime modérée, mais quelques profils très risqués (véhicule puissant, zone très urbaine, historique chargé) font monter la moyenne. En pratique, l’assureur fixe une prime commerciale en ajoutant à cette prime pure des chargements pour frais de gestion, marge de sécurité et profit.
Ce projet illustre la chaîne complète de tarification actuarielle en assurance automobile :
La méthodologie utilisée ici est directement transposable au marché tunisien, où les société d’assuarnce tunisiennes utilisent des approches similaires dans le cadre réglementaire du CGA. L’enjeu pour le marché tunisien est d’affiner ces modèles avec des données locales — densité de trafic par gouvernorat, état du parc automobile, profil démographique des conducteurs — pour une tarification plus équitable et plus précise.
mini-projet réalisé par Eya Douiri Future actuaire et data scientist ❤️ contact :eyadouiri9@gmail.com