Régression pénalisée en R : ridge, lasso et elastic net avec glmnet
Rétractez les coefficients, sélectionnez les variables et maîtrisez la multicolinéarité — réglée honnêtement par validation croisée
Un guide pratique de la régression pénalisée (régularisée) en R : ridge (L2), lasso (L1) et elastic net. Découvrez comment chacune rétracte les coefficients, pourquoi le lasso en met certains exactement à zéro (sélection de variables), et comment régler la pénalité lambda par validation croisée. Traité de deux façons — le workflow tidymodels moderne avec parsnip + glmnet, et la voie classique glmnet::cv.glmnet — avec des graphiques de chemins de coefficients et de courbe de validation croisée expliqués en langage clair. Sur les données Boston intégrées.
Date de publication
25 juin 2026
Modifié
7 juillet 2026
AstuceL’essentiel à retenir
La régression pénalisée (alias régularisation ou rétraction) ajoute une pénalité sur la taille des coefficients à la régression des moindres carrés ordinaires. Elle rétracte les prédicteurs faibles vers zéro — le remède aux trop-nombreuses-variables, à la multicolinéarité et au surapprentissage.
Le ridge (L2) rétracte chaque coefficient vers zéro mais les conserve tous. Le lasso (L1) rétracte et met certains coefficients exactement à zéro — il fait donc de la sélection de variables. L’elastic net mélange les deux (le mixture entre 0 et 1).
L’ampleur de la rétraction tient en un seul paramètre de réglage, lambda (penalty). λ = 0 correspond aux moindres carrés ordinaires ; à mesure que λ grandit, les coefficients se rétractent vers zéro. Vous choisissez λ par validation croisée.
Standardisez d’abord les prédicteurs — les pénalités agissent sur la taille des coefficients, donc les prédicteurs doivent être à une échelle commune (step_normalize(), ou le standardize = TRUE intégré de glmnet).
Deux voies, un même résultat : le workflow tidymodels moderne (linear_reg(penalty = tune(), mixture =) |> set_engine("glmnet")) réglé avec tune_grid(), ou le classique glmnet::cv.glmnet() — qui vous fournit lambda.min (erreur de validation croisée la plus faible) et lambda.1se (le modèle le plus simple à une erreur standard près).
Lisez les deux lambdas :lambda.min prédit le mieux ; lambda.1se est plus agressif (plus de zéros, modèle plus simple) au prix d’une infime perte de précision — souvent le meilleur choix quand vous voulez un modèle interprétable.
La régression des moindres carrés ordinaires a un point faible : quand vous avez beaucoup de prédicteurs — surtout plus de prédicteurs que d’observations, ou des prédicteurs corrélés entre eux — ses estimations de coefficients deviennent instables et elle surapprend, ajustant le bruit d’entraînement et prédisant mal les nouvelles données.
La régression pénalisée corrige cela en ajoutant une contrainte au problème d’ajustement : une pénalité sur la taille des coefficients. Le modèle n’est plus libre de rendre un coefficient aussi grand que les données d’entraînement le suggèrent — les grands coefficients lui coûtent, donc il les rétracte vers zéro, ne gardant que le signal qui mérite vraiment sa place. On appelle aussi cela régularisation ou rétraction, et c’est l’un des moyens les plus fiables de construire un modèle qui prédit bien hors échantillon.
Cette leçon couvre les trois chevaux de bataille — ridge, lasso et elastic net — ce que chacun fait à vos coefficients, et comment choisir honnêtement la pénalité par validation croisée. Nous le traitons de deux façons : le workflow tidymodels moderne (parsnip + glmnet), et la voie classique glmnet::cv.glmnet() que la plupart des utilisateurs de R apprennent en premier. Pour le contexte plus large du machine learning, voir construire des modèles avec tidymodels et validation croisée ; pour l’alternative de sélection de variables qui retire les prédicteurs un à un, voir régression pas à pas.
NoteQuand y recourir
Utilisez la régression pénalisée quand vous avez beaucoup de prédicteurs, des prédicteurs corrélés (multicolinéarité), ou un modèle qui obtient de bons scores à l’entraînement mais de mauvais sur de nouvelles données. Recourez au lasso quand vous soupçonnez que seule une poignée de prédicteurs comptent vraiment (vous voulez un modèle parcimonieux, interprétable) ; au ridge quand de nombreux prédicteurs contribuent chacun un peu ; et à l’elastic net quand les prédicteurs sont corrélés et que vous voulez tout de même une sélection.
Les données
Nous utilisons le jeu de données intégré Boston du package MASS : 506 banlieues de Boston, avec pour objectif de prédire medv — la valeur médiane du logement (en milliers de dollars) — à partir de 13 prédicteurs socio-économiques et structurels (taux de criminalité crim, nombre moyen de pièces rm, ratio élèves–enseignant ptratio, % population de statut inférieurlstat, etc.). Plusieurs de ces prédicteurs sont corrélés, ce qui est exactement le cadre où la pénalisation prouve son utilité.
Nous séparons les données en un jeu d’entraînement (80 %, pour l’ajustement et le réglage) et un jeu de test (20 %, mis de côté pour juger honnêtement le modèle final). Nous stratifions sur medv pour que les deux jeux aient une distribution de sortie similaire, et fixons une graine pour la reproductibilité :
library(rsample)data("Boston", package ="MASS")# 506 Boston suburbs: predict median home value (medv) from 13 predictorsset.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)test_data <-testing(split)c(train =nrow(train_data), test =nrow(test_data), predictors =ncol(Boston) -1)
Environ 400 banlieues pour apprendre, 100 mises de côté pour faire office de juge, et 13 prédicteurs à rétracter.
Le workflow tidymodels : ridge, lasso, elastic net
Dans tidymodels, les trois méthodes sont une seule spécification de modèle avec deux boutons. parsnip::linear_reg() prend un penalty (c’est lambda — combien rétracter) et un mixture (le mélange de l’elastic net) :
mixture = 0 → ridge pur (pénalité L2)
mixture = 1 → lasso pur (pénalité L1)
0 < mixture < 1 → elastic net (par ex. 0.5 est un mélange moitié-moitié)
Le moteur est "glmnet". Les méthodes pénalisées exigent des prédicteurs standardisés (la pénalité agit sur la taille des coefficients, donc les prédicteurs doivent partager une échelle), aussi le recipe les normalise-t-il d’abord — c’est l’étape de feature engineering dont tout modèle pénalisé a besoin.
Régler la pénalité par validation croisée (lasso)
Nous ne devinons pas lambda — nous laissons la validation croisée le choisir. Marquez penalty = tune(), construisez une grille de valeurs candidates, et notez chacune par une validation croisée à 10 plis sur le jeu d’entraînement. mixture = 1 en fait un lasso :
library(rsample)library(recipes)library(parsnip)library(workflows)library(tune)library(dials)library(yardstick)data("Boston", package ="MASS")set.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)# Standardize predictors — penalized methods require a common scalerec <-recipe(medv ~ ., data = train_data) |>step_normalize(all_numeric_predictors())# Lasso: mixture = 1, penalty left to be tunedlasso_spec <-linear_reg(penalty =tune(), mixture =1) |>set_engine("glmnet")lasso_wf <-workflow() |>add_recipe(rec) |>add_model(lasso_spec)# 10-fold CV on the training set, over a grid of lambda valuesset.seed(123)folds <-vfold_cv(train_data, v =10)grid <-grid_regular(penalty(range =c(-3, 0)), levels =50) # 10^-3 to 10^0set.seed(123)lasso_tuned <-tune_grid( lasso_wf, resamples = folds, grid = grid,metrics =metric_set(rmse, rsq))# The lambda with the lowest cross-validated RMSEbest_lambda <-select_best(lasso_tuned, metric ="rmse")best_lambda
tune_grid() a validé par validation croisée chaque lambda candidat ; select_best() renvoie celui dont l’erreur de validation croisée est la plus faible. Ici la meilleure pénalité est petite (≈ 0.001) — sur ce jeu de données une touche légère prédit le mieux, mais comme nous le verrons, une pénalité un peu plus lourde achète un modèle bien plus simple pour presque aucun coût en précision.
La courbe de validation croisée : erreur en fonction de lambda
Le graphique le plus utile de la régression pénalisée est l’erreur de validation croisée en fonction de lambda. Il montre tout le compromis biais–variance en une seule image :
library(ggplot2)# Collect the CV metric for every candidate lambdalasso_metrics <-collect_metrics(lasso_tuned)rmse_curve <-subset(lasso_metrics, .metric =="rmse")ggplot(rmse_curve, aes(x = penalty, y = mean)) +geom_line(color ="#3a86d4", linewidth =1) +geom_point(color ="#3a86d4", size =1.5) +geom_vline(xintercept = best_lambda$penalty, linetype ="dashed", color ="gray40") +scale_x_log10() +labs(x =expression("Penalty "* lambda *" (log scale)"),y ="Cross-validated RMSE",title ="Choosing the penalty by cross-validation",subtitle ="Error is flat for light penalties, then climbs as lambda over-shrinks (dashed = best lambda)" ) +theme_minimal()
Lisez-le de gauche à droite. Pour un petit lambda (à gauche), la pénalité mord à peine — le modèle est proche des moindres carrés ordinaires et l’erreur est faible mais un peu variable. À mesure que lambda grandit (à droite), les coefficients sont forcés vers zéro ; passé un certain point le modèle est trop contraint (sous-apprentissage) et l’erreur grimpe fortement. La ligne en tirets marque le vainqueur de la validation croisée — le juste milieu entre le surapprentissage (trop peu de pénalité) et le sous-apprentissage (trop).
Le chemin des coefficients : voyez le lasso sélectionner les variables
L’autre graphique caractéristique est le chemin des coefficients — chaque coefficient tracé à mesure que lambda augmente. C’est là que le comportement déterminant du lasso est visible : les coefficients ne font pas que se rétracter, ils atteignent exactement zéro et y restent. Un prédicteur dont le chemin est tombé à zéro a été retiré du modèle.
library(glmnet)library(rsample)data("Boston", package ="MASS")set.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)# glmnet wants a numeric predictor matrix (no intercept column) + an outcome vectorx <-model.matrix(medv ~ ., train_data)[, -1]y <- train_data$medv# Fit lasso (alpha = 1) over a whole sequence of lambdas; standardize = TRUE by defaultlasso_full <-glmnet(x, y, alpha =1, standardize =TRUE)plot(lasso_full, xvar ="lambda", label =TRUE)title("Lasso coefficient paths (Boston)", line =2.5)
Chaque courbe est un prédicteur. En lisant de droite à gauche (pénalité croissante → décroissante) : à une forte pénalité (à l’extrême droite) presque tous les coefficients sont nuls ; à mesure que la pénalité se relâche, les prédicteurs « s’allument » un à un à peu près dans leur ordre d’importance. Le nombre le long de l’axe supérieur indique combien de prédicteurs restent non nuls à ce lambda. C’est la sélection de variables qui se produit en continu — la fonction phare que le lasso possède et que le ridge n’a pas.
NoteLe ridge a l’air différent — il n’atteint jamais zéro
Relancez le chemin avec alpha = 0 (ridge) et les lignes glissent ensemble vers zéro mais ne le touchent jamais — le ridge conserve chaque prédicteur, simplement plus petit. Cette unique différence visuelle est toute l’histoire : le lasso sélectionne, le ridge ne fait que rétracter. L’elastic net (0 < alpha < 1) se situe entre les deux.
Finaliser et évaluer sur le jeu de test
Nous choisissons le meilleur lambda, finalisons le workflow, et faisons last_fit() — ajustement sur toutes les données d’entraînement et évaluation une seule fois sur le jeu de test intact. Le tableau ordonné des coefficients montre quels prédicteurs ont survécu :
library(rsample)library(recipes)library(parsnip)library(workflows)library(tune)library(dials)library(yardstick)library(broom)data("Boston", package ="MASS")set.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)rec <-recipe(medv ~ ., data = train_data) |>step_normalize(all_numeric_predictors())lasso_spec <-linear_reg(penalty =tune(), mixture =1) |>set_engine("glmnet")lasso_wf <-workflow() |>add_recipe(rec) |>add_model(lasso_spec)set.seed(123); folds <-vfold_cv(train_data, v =10)grid <-grid_regular(penalty(range =c(-3, 0)), levels =50)set.seed(123)lasso_tuned <-tune_grid(lasso_wf, resamples = folds, grid = grid,metrics =metric_set(rmse, rsq))best_lambda <-select_best(lasso_tuned, metric ="rmse")# Finalize with the chosen lambda, fit on train, score ONCE on testfinal_fit <-finalize_workflow(lasso_wf, best_lambda) |>last_fit(split)collect_metrics(final_fit)
# A tibble: 2 × 4
.metric .estimator .estimate .config
<chr> <chr> <dbl> <chr>
1 rmse standard 4.88 pre0_mod0_post0
2 rsq standard 0.714 pre0_mod0_post0
Lisez les chiffres (la performance honnête et hors échantillon de votre modèle) :
RMSE ≈ 4.9 — une prédiction typique de la valeur médiane du logement se trompe d’environ 4 900 $ (la sortie est en milliers de dollars). Plus bas, mieux c’est ; c’est le nombre sur lequel comparer les modèles.
R² ≈ 0.71 — le modèle explique environ 71 % de la variance de la valeur médiane du logement sur des banlieues qu’il n’a jamais vues pendant l’ajustement. Solide pour un modèle linéaire sur ces données.
Et les coefficients survivants (à l’échelle standardisée, donc directement comparables en taille) :
library(broom)# The coefficients of the finalized lasso modeltidy(extract_fit_parsnip(final_fit$.workflow[[1]]))
Les plus grands coefficients — lstat (% population de statut inférieur), rm (pièces), dis (distance aux centres d’emploi) — sont les prédicteurs sur lesquels le modèle s’appuie le plus. Comme nous avons réglé sur une pénalité légère ici, peu de coefficients ont été poussés entièrement à zéro ; la section suivante montre comment une pénalité un peu plus lourde achète un modèle véritablement parcimonieux.
La voie classique : glmnet::cv.glmnet
La plupart des utilisateurs de R rencontrent la régression pénalisée à travers glmnet directement. cv.glmnet() fait la validation croisée pour vous et renvoie deux lambdas utiles. C’est la voie qui vaut la peine d’être connue parce qu’elle rend explicite le choix entre lambda.min et lambda.1se :
library(glmnet)library(rsample)data("Boston", package ="MASS")set.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)test_data <-testing(split)# glmnet works on a numeric matrix + outcome vectorx <-model.matrix(medv ~ ., train_data)[, -1]y <- train_data$medvx_test <-model.matrix(medv ~ ., test_data)[, -1]# Lasso (alpha = 1) with built-in 10-fold cross-validationset.seed(123)cv_lasso <-cv.glmnet(x, y, alpha =1) # standardize = TRUE by defaultc(lambda.min = cv_lasso$lambda.min, lambda.1se = cv_lasso$lambda.1se)
lambda.min lambda.1se
0.006976771 0.347235533
Deux lambdas, deux philosophies :
lambda.min — le lambda dont l’erreur de validation croisée est la plus faible. Prédit le mieux, mais conserve plus de prédicteurs.
lambda.1se — le plus grand lambda dont l’erreur reste à une erreur standard près du minimum. Un peu plus d’erreur, mais un modèle plus simple, pénalisé plus agressivement (plus de zéros). Le choix conventionnel quand vous valorisez l’interprétabilité et la robustesse.
Regardez les coefficients à lambda.1se — la pénalisation comme sélection de variables sous vos yeux :
library(glmnet)library(rsample)data("Boston", package ="MASS")set.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)x <-model.matrix(medv ~ ., train_data)[, -1]y <- train_data$medvset.seed(123); cv_lasso <-cv.glmnet(x, y, alpha =1)# Coefficients at the simpler 1-SE model: dots are predictors dropped (= zero)coef(cv_lasso, s ="lambda.1se")
14 x 1 sparse Matrix of class "dgCMatrix"
lambda.1se
(Intercept) 16.513093237
crim -0.007284334
zn .
indus .
chas 2.606472873
nox -4.135548263
rm 4.443731663
age .
dis -0.331671833
rad .
tax .
ptratio -0.798716237
black 0.006918224
lstat -0.492410327
Plusieurs prédicteurs — zn, indus, age, rad, tax — affichent un . : leur coefficient est exactement zéro, donc le lasso les a retirés du modèle. De 13 prédicteurs à une poignée, automatiquement. Ce modèle plus parcimonieux est plus facile à expliquer et généralise souvent tout aussi bien.
Maintenant évaluons les deux lambdas sur le jeu de test pour voir le compromis en chiffres :
library(glmnet)library(rsample)library(yardstick)data("Boston", package ="MASS")set.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)test_data <-testing(split)x <-model.matrix(medv ~ ., train_data)[, -1]y <- train_data$medvx_test <-model.matrix(medv ~ ., test_data)[, -1]set.seed(123); cv_lasso <-cv.glmnet(x, y, alpha =1)# Predict at each lambda, then score on the held-out test setpred_min <-as.vector(predict(cv_lasso, newx = x_test, s ="lambda.min"))pred_1se <-as.vector(predict(cv_lasso, newx = x_test, s ="lambda.1se"))data.frame(lambda =c("lambda.min", "lambda.1se"),RMSE =c(rmse_vec(test_data$medv, pred_min), rmse_vec(test_data$medv, pred_1se)),R2 =c(rsq_vec(test_data$medv, pred_min), rsq_vec(test_data$medv, pred_1se)))
lambda.min donne le RMSE le plus bas (≈ 4.9, R² ≈ 0.71) — la meilleure prédiction. lambda.1se coûte un peu de précision (RMSE ≈ 5.3, R² ≈ 0.67) mais en échange vous obtenez le modèle bien plus simple ci-dessus. Voilà la décision centrale de la régression pénalisée : combien de précision êtes-vous prêt à échanger contre de la simplicité ? La validation croisée vous remet les deux options ; vous choisissez selon votre objectif.
Ridge et elastic net : changez un seul argument
Tout ce qui précède était du lasso (mixture = 1 / alpha = 1). Les deux autres méthodes changent un seul argument — le workflow est par ailleurs identique :
library(rsample)library(recipes)library(parsnip)library(workflows)library(tune)library(dials)library(yardstick)data("Boston", package ="MASS")set.seed(123)split <-initial_split(Boston, prop =0.80, strata = medv)train_data <-training(split)rec <-recipe(medv ~ ., data = train_data) |>step_normalize(all_numeric_predictors())set.seed(123); folds <-vfold_cv(train_data, v =10)grid <-grid_regular(penalty(range =c(-3, 0)), levels =50)# Helper: tune a penalized model at a given mixture, return test-set RMSE / R2score_penalized <-function(mixture) { spec <-linear_reg(penalty =tune(), mixture = mixture) |>set_engine("glmnet") wf <-workflow() |>add_recipe(rec) |>add_model(spec)set.seed(123) tuned <-tune_grid(wf, resamples = folds, grid = grid, metrics =metric_set(rmse, rsq)) best <-select_best(tuned, metric ="rmse") m <-collect_metrics(finalize_workflow(wf, best) |>last_fit(split))data.frame(RMSE = m$.estimate[m$.metric =="rmse"],R2 = m$.estimate[m$.metric =="rsq"])}rbind(Ridge =score_penalized(0), # L2 only — keeps all predictors`Elastic net`=score_penalized(0.5), # L1 + L2 blendLasso =score_penalized(1) # L1 only — selects predictors)
Sur les données Boston les trois sont quasi identiques en précision (RMSE ≈ 4.9–5.0, R² ≈ 0.70–0.71) — ce qui est courant, et en soi une conclusion utile. Quand la précision prédictive est à égalité, préférez le modèle le plus simple : le lasso ou l’elastic net, qui ont retiré des prédicteurs (par ex. age), plutôt que le ridge, qui garde les 13. Toutes choses égales par ailleurs, optez pour le modèle le plus simple.
NoteLequel devrais-je utiliser ?
Lasso quand vous pensez que seuls quelques prédicteurs comptent — il donne un modèle parcimonieux et interprétable.
Ridge quand de nombreux prédicteurs contribuent chacun un peu et que vous voulez tous les conserver (il gère aussi élégamment la multicolinéarité en répartissant la charge entre prédicteurs corrélés).
Elastic net quand les prédicteurs sont corréléset que vous voulez tout de même une sélection — il regroupe les prédicteurs corrélés au lieu d’en choisir un arbitrairement (la faiblesse du lasso). Réglez aussi mixture si vous hésitez : laissez la validation croisée choisir le mélange.
NoteLes mathématiques derrière la pénalité (optionnel)
Les moindres carrés ordinaires choisissent les coefficients β qui minimisent la somme des carrés des résidus, \(RSS\). La régression pénalisée ajoute une pénalité sur les tailles des coefficients :
La pénalité L2 (ridge) est lisse, donc elle rétracte les coefficients mais ne les force jamais exactement à zéro. La pénalité L1 (lasso) a un coin à zéro, et c’est ce coin qui lui permet de mettre des coefficients exactement à zéro — la raison géométrique pour laquelle le lasso sélectionne les variables et le ridge non. L’elastic net mélange les deux avec \(\alpha\) (= mixture) : \(\alpha = 1\) est le lasso, \(\alpha = 0\) est le ridge. Dans tous les cas \(\lambda\) (= penalty) est le cadran choisi par validation croisée ; λ = 0 retrouve les moindres carrés ordinaires. Parce que la pénalité compare les tailles des coefficients, les prédicteurs doivent d’abord être standardisés — sinon un prédicteur mesuré en petites unités serait pénalisé plus lourdement du seul fait de son échelle.
Vous venez de caret ? La correspondance
Si vous avez appris la régression pénalisée avec le train(method = "glmnet") de caret, les idées se transposent directement — seuls les verbes changent. tidymodels fait de la pénalité et du mixture des paramètres de réglage explicites :
fit_resamples() / collect_metrics() sur des plis partagés
alpha dans glmnet/caret estmixture dans parsnip ; lambdaestpenalty. Tout le reste est le même enchaînement split → recipe → tune → finalize que vous connaissez déjà.
🟢 Avec un agent IA
Vous avez un modèle avec trop de prédicteurs corrélés ? Demandez à Prova« ajuste un lasso à ces données, règle la pénalité par validation croisée, et dis-moi quels prédicteurs il conserve » — elle répond avec du code tidymodels + glmnet que vous pouvez exécuter sur vos propres données, puis vous aide à lire le chemin des coefficients et à choisir lambda.min vs lambda.1se. The runtime is the judge.Ask Prova →
Problèmes courants
Vous avez oublié de standardiser les prédicteurs. Les pénalités agissent sur la taille des coefficients, donc un prédicteur en grandes unités est injustement moins rétracté. Mettez toujours step_normalize(all_numeric_predictors()) dans le recipe (ou comptez sur le standardize = TRUE par défaut de glmnet). Les coefficients sont tout de même rapportés à l’échelle d’origine, donc ils restent interprétables.
glmnet renvoie une erreur sur des facteurs ou un x non numérique.glmnet() a besoin d’une matrice de modèle numérique. Construisez-la avec model.matrix(y ~ ., data)[, -1] (le [, -1] retire la colonne d’ordonnée à l’origine), ce qui transforme aussi les facteurs en variables indicatrices. Dans un recipe tidymodels, ajoutez step_dummy(all_nominal_predictors()).
Votre « meilleur » lambda se situe au bord de la grille. Cela signifie que la grille est trop étroite — élargissez penalty(range = c(...)) (elle est sur une échelle log10) jusqu’à ce que la courbe de validation croisée montre un minimum clair à l’intérieur de la plage, et non à une extrémité.
Deux exécutions donnent des lambdas légèrement différents. La répartition des plis de validation croisée est aléatoire. Appelez set.seed() avant vfold_cv() / cv.glmnet() pour un résultat reproductible.
Foire aux questions
NoteComment faire une régression ridge en R ?
Utilisez glmnet avec alpha = 0 : cv.glmnet(x, y, alpha = 0) pour choisir la pénalité par validation croisée, puis glmnet(x, y, alpha = 0, lambda = cv$lambda.min) pour le modèle final. En tidymodels : linear_reg(penalty = tune(), mixture = 0) |> set_engine("glmnet") dans un workflow avec step_normalize(), réglé par tune_grid(). Le ridge rétracte chaque coefficient mais conserve tous les prédicteurs.
NoteComment faire une régression lasso en R ?
Comme le ridge mais avec alpha = 1 (glmnet) ou mixture = 1 (tidymodels). cv.glmnet(x, y, alpha = 1) valide la pénalité par validation croisée ; coef() à lambda.1se montre quels prédicteurs le lasso a conservés et lesquels il a mis exactement à zéro. Contrairement au ridge, le lasso effectue une sélection de variables — il retire les prédicteurs faibles du modèle.
NoteComment exécuter une régression elastic net en R ?
L’elastic net mélange les pénalités L1 (lasso) et L2 (ridge). Dans glmnet, fixez alpha entre 0 et 1 (par ex. alpha = 0.5). Dans tidymodels, utilisez linear_reg(penalty = tune(), mixture = tune()) et laissez tune_grid() chercher à la fois la pénalité et le mixture. C’est le meilleur choix quand les prédicteurs sont corrélés et que vous voulez tout de même une sélection.
NoteQu’est-ce que la régression pénalisée et quand devrais-je l’utiliser ?
La régression pénalisée (régularisée) ajoute une pénalité sur la taille des coefficients à la régression des moindres carrés ordinaires, rétractant les prédicteurs faibles vers zéro. Utilisez-la quand vous avez beaucoup de prédicteurs, des prédicteurs corrélés (multicolinéarité), ou un modèle qui surapprend — la pénalisation stabilise les estimations et prédit généralement mieux sur de nouvelles données. Le ridge, le lasso et l’elastic net sont les trois variantes standard.
NoteÀ quoi sert le package glmnet ?
glmnet est le package R standard pour la régression et la classification pénalisées. glmnet(x, y, alpha, lambda) ajuste le ridge (alpha = 0), le lasso (alpha = 1), ou l’elastic net (entre les deux) sur une séquence de pénalités ; cv.glmnet() ajoute une validation croisée intégrée et renvoie lambda.min (erreur de validation croisée la plus faible) et lambda.1se (le modèle le plus simple à une erreur standard près). Il a besoin d’une matrice de prédicteurs numérique et standardise les prédicteurs par défaut.
NoteQuelle est la différence entre lambda.min et lambda.1se ?
Les deux viennent de cv.glmnet(). lambda.min est la pénalité dont l’erreur de validation croisée est la plus faible — elle prédit le mieux mais conserve plus de prédicteurs. lambda.1se est la plus grande pénalité dont l’erreur reste à une erreur standard près du minimum — un modèle un peu moins précis mais plus simple, plus régularisé (plus de coefficients mis à zéro). Choisissez lambda.min pour la précision brute, lambda.1se pour un modèle plus simple et plus robuste.
Testez votre compréhension
ImportantExercice : réglez un modèle ridge et comparez-le au lasso
En utilisant les données Boston (MASS), construisez un modèle ridge (mixture = 0) à la manière tidymodels : séparez 80/20 stratifié sur medv, normalisez les prédicteurs, réglez penalty par validation croisée à 10 plis, et rapportez le RMSE et le R² du jeu de test. Comment se compare-t-il au lasso de la leçon — et le ridge retire-t-il des prédicteurs ?
AstuceIndice
La forme est identique au workflow du lasso — changez seulement mixture = 1 en mixture = 0. Vous aurez besoin de rsample, recipes, parsnip, workflows, tune, dials et yardstick. Pour vérifier les prédicteurs retirés, regardez le tidy() de l’ajustement finalisé — le ridge les conservera tous (aucun zéro).
Vous obtiendrez un RMSE autour de 5.0 et un R² autour de 0.70 — essentiellement la même précision que le lasso. La différence clé est dans les coefficients : le ridge conserve les 13 prédicteurs (aucun mis à zéro), tandis que le lasso en a retiré plusieurs. Quand la précision est à égalité, le modèle lasso/elastic net est le plus simple, le préférable.
Vérification rapide. Vous ajustez un lasso et un ridge aux mêmes données et ils prédisent aussi bien l’un que l’autre, mais le modèle lasso a cinq coefficients exactement à zéro tandis que le modèle ridge n’en a aucun. Quel modèle expédieriez-vous, et pourquoi ?
NoteAfficher la réponse
Expédiez le modèle lasso. Quand deux modèles prédisent aussi bien, préférez le plus simple : les cinq zéros du lasso signifient qu’il utilise moins de prédicteurs, donc il est plus facile à expliquer, moins coûteux en collecte de données, et moins susceptible de surapprendre par la suite. Le ridge conserve chaque prédicteur, ce qui ajoute de la complexité sans gain de précision ici. Toutes choses égales par ailleurs, optez pour le modèle le plus simple.
Conclusion
Vous avez vu la régression pénalisée de bout en bout sur les données Boston : le ridge (L2) rétracte chaque coefficient mais les conserve tous ; le lasso (L1) rétracte et met certains exactement à zéro, faisant de la sélection de variables ; l’elastic net mélange les deux. Vous avez réglé la pénalité lambda honnêtement par validation croisée — à la fois la manière moderne (linear_reg(penalty = tune(), mixture =) |> set_engine("glmnet") + tune_grid()) et la voie classique cv.glmnet() — lu la courbe d’erreur de validation croisée et le chemin des coefficients, et pesé lambda.min (meilleure prédiction) contre lambda.1se (modèle plus simple). La règle pratique : standardisez d’abord, laissez la validation croisée choisir lambda, et quand la précision est à égalité, expédiez le modèle le plus simple.
Prouvez que vous savez le faire. Maîtrisez toute la série Sélection de modèles en R — suivez votre parcours, construisez des projets et obtenez un certificat.
Cette leçon est reproductible : chaque coefficient, métrique et figure a été produit par le code montré — copiez n’importe quel bloc et exécutez-le pour les reproduire. The runtime is the judge.
Références
James, G., Witten, D., Hastie, T., & Tibshirani, R. (2014). An Introduction to Statistical Learning, with Applications in R. Springer. (Chapitre 6 — Sélection et régularisation des modèles linéaires.)
Friedman, J., Hastie, T., & Tibshirani, R. (2010). Regularization Paths for Generalized Linear Models via Coordinate Descent. Journal of Statistical Software, 33(1). (Le package glmnet.)
Kuhn, M., & Silge, J. Tidy Modeling with R. En ligne, gratuit (CC BY-NC-SA).
@online{2026,
author = {},
title = {Régression pénalisée en R : ridge, lasso et elastic net avec
glmnet},
date = {2026-06-25},
url = {https://www.datanovia.com/learn/machine-learning/model-selection/penalized-regression},
langid = {fr}
}