1 Contexte et objectif

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

2 Exploration des données

2.1 Structure du dataset

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.

2.2 Distribution du nombre de sinistres

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.

2.3 Fréquence selon l’âge du conducteur

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.

2.4 Fréquence selon la zone géographique

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.

3 Modèle de fréquence — GLM Poisson

3.1 Justification du choix

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.

3.2 Ajustement du modèle

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

3.3 Interprétation des coefficients

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.

4 Modèle de coût — GLM Gamma

4.1 Justification du choix

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.

4.2 Ajustement du modèle

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

4.3 Interprétation

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.

5 Calcul de la prime pure

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.

6 Conclusion

Ce projet illustre la chaîne complète de tarification actuarielle en assurance automobile :

  1. On modélise la fréquence des sinistres avec un GLM Poisson, en tenant compte de l’exposition et des caractéristiques du conducteur et du véhicule.
  2. On modélise le coût moyen des sinistres avec un GLM Gamma, sur le sous-ensemble des polices sinistrées.
  3. On combine les deux pour obtenir une prime pure individuelle, qui reflète le risque réel de chaque assuré.

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 :