Une implémentation du gradient boosting conçue par Microsoft pour aller vite sur de gros volumes. Elle regroupe les valeurs de chaque variable en tranches et fait pousser ses arbres feuille par feuille. Sur de gros volumes, LightGBM entraîne nettement plus vite qu'un gradient boosting classique, pour une précision comparable à XGBoost.
Plutôt que de trier chaque âge au jour près, on range les conducteurs dans 255 tranches d'âge au maximum. On cherche ensuite la meilleure coupure parmi ces tranches, ce qui va beaucoup plus vite et perd très peu d'information.
Avant l'entraînement, chaque variable numérique est résumée en un histogramme de quelques centaines de tranches au maximum. Les calculs portent ensuite sur ces tranches, pas sur chaque ligne.
Au lieu de remplir chaque étage de l'arbre, LightGBM découpe à chaque fois la feuille qui réduit le plus l'erreur. Les arbres deviennent asymétriques et plus efficaces, à condition de limiter leur nombre de feuilles.
Chaque nouvel arbre corrige l'erreur restante, avec un petit pas d'apprentissage. L'arrêt précoce stoppe l'ajout d'arbres quand le score de validation ne progresse plus.
Âge du conducteur, puissance du véhicule, zone, bonus-malus, durée d'exposition. La cible est le coût total des sinistres de l'année, nul pour la grande majorité des contrats.
C'est la prime pure : ce que le contrat coûtera en moyenne, avant frais et marge. La perte Tweedie gère à la fois la masse de zéros et les quelques sinistres coûteux, sans séparer fréquence et coût moyen.
On classe les contrats de test par prime prédite, en 5 groupes. Un bon modèle montre un coût observé nettement plus élevé dans le dernier quintile que dans le premier. Sur un petit jeu comme celui-ci, les quintiles du milieu restent bruités.
Noms donnés pour R (lgb.train) et Python (LGBMRegressor), qui partagent le même moteur.
Le nombre maximal de feuilles par arbre, 31 par défaut. C'est le réglage principal de la complexité, puisque les arbres poussent feuille par feuille. Sur des données bruitées comme l'assurance, 8 à 16 suffisent.
Le nombre minimum de lignes par feuille, 20 par défaut. L'augmenter (100 ou plus) évite qu'une feuille repose sur quelques sinistres isolés.
Pas de 0,1 par défaut. On le baisse (0,03), on fixe un nombre d'arbres large et on arrête quand le score de validation ne progresse plus depuis 100 tours.
La perte : binary pour oui / non, poisson pour un comptage, tweedie pour un coût avec beaucoup de zéros. tweedie_variance_power, entre 1 et 2, règle le compromis ; 1,5 est un point de départ courant.
# Prime pure auto : LightGBM en R
library(lightgbm)
contrats <- read.csv("sinistres.csv")
contrats$zone <- as.integer(factor(contrats$zone)) - 1L # codes 0, 1, 2 déclarés catégoriels
X <- as.matrix(contrats[, c("age_conducteur", "puissance_cv", "zone", "bonus_malus")])
y <- contrats$cout_total / contrats$exposition # coût par année d'assurance
w <- contrats$exposition
# 60 % apprentissage, 20 % validation (arrêt précoce), 20 % test
set.seed(42)
groupe <- sample(c("fit", "valid", "test"), nrow(X), replace = TRUE, prob = c(0.6, 0.2, 0.2))
dfit <- lgb.Dataset(X[groupe == "fit", ], label = y[groupe == "fit"], weight = w[groupe == "fit"],
categorical_feature = "zone")
dvalid <- lgb.Dataset.create.valid(dfit, X[groupe == "valid", ], label = y[groupe == "valid"],
weight = w[groupe == "valid"])
# Perte Tweedie : beaucoup de zéros, quelques coûts élevés
params <- list(objective = "tweedie", tweedie_variance_power = 1.5, learning_rate = 0.03,
num_leaves = 8, min_data_in_leaf = 100, seed = 42, verbose = -1)
modele <- lgb.train(params = params, data = dfit, nrounds = 2000, valids = list(valid = dvalid),
early_stopping_rounds = 100, verbose = -1)
cat("Arbres retenus :", modele$best_iter, "\n")
# Coût annuel observé et prédit par quintile de risque, sur les contrats jamais vus
test <- contrats[groupe == "test", ]
test$prime <- predict(modele, X[groupe == "test", ])
quintile <- cut(rank(test$prime, ties.method = "first"), 5, labels = 1:5)
observe <- tapply(test$cout_total, quintile, sum) / tapply(test$exposition, quintile, sum)
predit <- tapply(test$prime * test$exposition, quintile, sum) / tapply(test$exposition, quintile, sum)
print(round(cbind(observe, predit)))
print(lgb.importance(modele))
# Prime pure auto : LightGBM en Python
import pandas as pd
import lightgbm as lgb
from sklearn.model_selection import train_test_split
contrats = pd.read_csv("sinistres.csv")
contrats["zone"] = contrats["zone"].astype("category") # catégorielle native, sans indicatrices
X = contrats[["age_conducteur", "puissance_cv", "zone", "bonus_malus"]]
y = contrats["cout_total"] / contrats["exposition"] # coût par année d'assurance
w = contrats["exposition"]
# 60 % apprentissage, 20 % validation (arrêt précoce), 20 % test
X_train, X_test, y_train, y_test, w_train, w_test = train_test_split(X, y, w, test_size=0.2, random_state=42)
X_fit, X_valid, y_fit, y_valid, w_fit, w_valid = train_test_split(X_train, y_train, w_train, test_size=0.25, random_state=42)
# Perte Tweedie : beaucoup de zéros, quelques coûts élevés
modele = lgb.LGBMRegressor(objective="tweedie", tweedie_variance_power=1.5, n_estimators=2000, learning_rate=0.03,
num_leaves=8, min_child_samples=100, random_state=42, verbose=-1)
modele.fit(X_fit, y_fit, sample_weight=w_fit, eval_set=[(X_valid, y_valid)], eval_sample_weight=[w_valid],
callbacks=[lgb.early_stopping(100, verbose=False)])
print("Arbres retenus :", modele.best_iteration_)
# Coût annuel observé et prédit par quintile de risque, sur les contrats jamais vus
test = pd.DataFrame({"expo": w_test, "cout": y_test * w_test, "pred": modele.predict(X_test) * w_test})
test["quintile"] = pd.qcut(test["pred"] / test["expo"], 5, labels=[1, 2, 3, 4, 5])
somme = test.groupby("quintile", observed=True)[["expo", "cout", "pred"]].sum()
print(somme[["cout", "pred"]].div(somme["expo"], axis=0).round(0))
print(pd.Series(modele.feature_importances_, index=X.columns).sort_values(ascending=False))
Les deux donnent des performances très proches une fois réglés. LightGBM est souvent plus rapide et plus économe en mémoire sur les gros volumes, et gère nativement les variables catégorielles. XGBoost est plus répandu dans les outils et un peu moins sensible au surapprentissage sur les petits jeux.
Il travaille sur des histogrammes : chaque variable est résumée en tranches avant l'entraînement, ce qui réduit fortement le nombre de coupures à tester. Il ajoute des astuces optionnelles, comme regrouper les variables rarement non nulles ou ne garder qu'une partie des lignes bien prédites à chaque tour.
Une variable déclarée catégorielle n'a pas besoin d'indicatrices 0 / 1. À chaque coupure, LightGBM trie les modalités selon leur effet sur l'erreur et cherche la meilleure partition en deux groupes. En Python, il suffit que la colonne soit de type category dans pandas.
Même famille, arbres construits étage par étage par défaut. Performances très proches ; le choix se fait souvent sur l'outillage en place.
Voir la fiche → pour les catégoriellesLe boosting qui encode lui-même les variables catégorielles. Plus robuste aux réglages par défaut, souvent plus lent à entraîner.
Voir la fiche → la référence actuarielleLe modèle de tarification historique, avec les mêmes lois (Poisson, Gamma, Tweedie). Moins précis, mais chaque coefficient se justifie.
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