Valeurs SHAP en R : expliquer les prédictions d’un modèle
Des attributions de variables issues de la théorie des jeux qui expliquent le modèle entier et une prédiction unique — de façon exécutable, sur vos propres données
Un guide pratique de SHAP (SHapley Additive exPlanations) en R. Calculez des valeurs SHAP indépendantes du modèle avec kernelshap, visualisez-les avec shapviz et lisez les deux moitiés de l’histoire : le récapitulatif global en essaim d’abeilles (quelles variables pilotent le modèle dans l’ensemble) et la cascade d’une prédiction unique (pourquoi CE patient a été signalé). Construit sur un classifieur de diabète par forêt aléatoire avec tidymodels sur les données PimaIndiansDiabetes2, avec une alternative DALEX et la propriété additive expliquée en langage clair.
Date de publication
25 juin 2026
Modifié
7 juillet 2026
AstucePoints clés
SHAP (SHapley Additive exPlanations) emprunte une idée à la théorie des jeux — la valeur de Shapley — pour répartir équitablement une prédiction unique entre les variables qui l’ont produite. Chaque variable reçoit un nombre signé : de combien elle a poussé cette prédiction vers le haut (vers le positif) ou vers le bas (vers le négatif).
SHAP répond aux deux questions d’explicabilité avec une seule méthode : la question globale « quelles variables pilotent le modèle dans l’ensemble ? » (moyenne des magnitudes — mean |SHAP|) et la question locale « pourquoi ce patient a-t-il été signalé ? » (lire les contributions d’une ligne). La plupart des outils d’importance ne font que la première.
La propriété qui la définit est l’additivité : pour toute prédiction unique, la valeur de base (la sortie moyenne du modèle) plus les contributions SHAP de cette ligne égale la prédiction du modèle. Aucun reste, aucune approximation vague — l’explication reconstruit le nombre exactement.
Calculez SHAP de manière indépendante du modèle avec kernelshap (fonctionne sur n’importe quel modèle ajusté — forêt aléatoire, xgboost, un réseau de neurones) et visualisez avec shapviz : un graphique beeswarm/récapitulatif pour la vue globale, un graphique en cascade (ou en force) pour une prédiction unique. DALEX::predict_parts(type = "shap") est une voie équivalente.
Sur les données de diabète Pima, SHAP confirme que glucose est le facteur dominant, avec mass (IMC), age et insulin ensuite — et, pour un patient spécifique, montre exactement quelles mesures ont fait pencher le verdict vers le positif ou le négatif. C’est l’avantage décisif de « the runtime is the judge » : un pourquoi exécutable et vérifiable pour n’importe quelle prédiction.
Un modèle qui prédit bien ne fait que la moitié du travail. Dès qu’il touche une décision réelle — signaler ce patient pour un test de diabète, refuser ce prêt, prioriser ce prospect — quelqu’un demande pourquoi. Non pas « quelles variables comptent en moyenne » (c’est l’importance des variables), mais pourquoi cette prédiction, pour cette ligne. Un modèle de forêt aléatoire ou de gradient boosting peut être très précis et complètement opaque à ce sujet.
SHAP est la méthode qui comble cet écart. Elle vient de la théorie des jeux coopératifs : imaginez que les variables sont des joueurs qui coopèrent pour produire une prédiction, et que vous voulez répartir le « gain » (à quel point la prédiction se situe loin de la moyenne) équitablement entre eux. La valeur de Shapley — un résultat qui a valu à Lloyd Shapley une part du prix Nobel d’économie 2012 — est l’unique répartition équitable. SHAP l’applique au machine learning : chaque variable, pour chaque prédiction, reçoit une contribution signée.
Ce qui rend SHAP spéciale, c’est que les mêmes nombres répondent aux deux questions d’explicabilité :
Globale — faites la moyenne de la magnitude des valeurs SHAP de chaque variable sur de nombreuses lignes (mean |SHAP|) et vous obtenez un classement d’importance rigoureux et indépendant du modèle.
Locale — lisez les valeurs SHAP d’une seule ligne et vous voyez exactement pourquoi cette prédiction unique a abouti comme elle l’a fait, variable par variable.
Et elle est additive : pour toute prédiction, la valeur de base (la sortie moyenne du modèle) plus les contributions SHAP de cette ligne égale la prédiction elle-même — l’explication s’additionne toujours pour redonner le nombre. Cette leçon calcule SHAP de manière indépendante du modèle avec kernelshap (qui fonctionne sur n’importe quel modèle ajusté), la visualise avec shapviz (le beeswarm global et la cascade d’une prédiction unique), et montre la voie DALEX équivalente. Nous expliquons un classifieur de diabète sur les données PimaIndiansDiabetes2 — et, chemin faisant, nous expliquons un patient spécifique.
NoteQuand recourir à SHAP
Recourez à SHAP lorsque vous devez expliquer des prédictions individuelles — le jour où une partie prenante, un régulateur, ou un clinicien demande « pourquoi le modèle a-t-il dit cela pour ce cas ? » C’est aussi une excellente mesure d’importance globale (plus rigoureuse qu’un seul passage de permutation). Préférez l’importance par permutation simple lorsque vous n’avez besoin que du classement global et que vous le voulez rapide ; recourez à la dépendance partielle & ICE lorsque vous voulez la forme de l’effet d’une variable (comment la prédiction change quand la variable varie), que SHAP résume mais ne dessine pas directement.
Les données et un modèle à expliquer
SHAP explique un modèle ajusté, il nous en faut donc un d’abord. Nous utilisons le jeu de données PimaIndiansDiabetes2 du package mlbench : 768 femmes d’origine amérindienne Pima, prédisant diabetes (une issue binaire pos/neg) à partir de huit prédicteurs cliniques — le nombre de grossesses (pregnant), le glucose plasmatique, la pressure artérielle, l’épaisseur du pli cutané au triceps, l’insulin sérique, l’indice de mass corporelle, la fonction pedigree de diabète, et l’age.
Cette version comporte des valeurs manquantes (des zéros invraisemblables enregistrés comme NA) ; en suivant l’analyse source, nous les supprimons, ce qui laisse 392 enregistrements complets, puis nous partitionnons en 80/20 stratifié sur diabetes afin que les deux ensembles conservent le même équilibre positif/négatif, avec une graine pour la reproductibilité :
library(rsample)data("PimaIndiansDiabetes2", package ="mlbench")# Drop rows with missing measurements (keeps the example simple and reproducible)pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)test_data <-testing(split)c(complete =nrow(pima), train =nrow(train_data), test =nrow(test_data))
complete train test
392 313 79
prop.table(table(train_data$diabetes)) # about a third are diabetes-positive
neg pos
0.6677316 0.3322684
Nous ajustons une forêt aléatoire — précise, mais une boîte noire quant aux prédictions individuelles, ce qui est exactement ce à quoi sert SHAP. Nous utilisons le workflow tidymodels moderne (parsnip + ranger) ; SHAP se moque de la façon dont le modèle a été construit, donc n’importe quel modèle ajusté conviendrait ici.
library(rsample)library(recipes)library(parsnip)library(workflows)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)test_data <-testing(split)# A 500-tree random forest, fitted through a tidymodels workflowrf_spec <-rand_forest(trees =500) |>set_engine("ranger") |>set_mode("classification")rf_wf <-workflow() |>add_recipe(recipe(diabetes ~ ., data = train_data)) |>add_model(rf_spec)set.seed(123)rf_fit <-fit(rf_wf, data = train_data)rf_fit
══ Workflow [trained] ══════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: rand_forest()
── Preprocessor ────────────────────────────────────────────────────────────────
0 Recipe Steps
── Model ───────────────────────────────────────────────────────────────────────
Ranger result
Call:
ranger::ranger(x = maybe_data_frame(x), y = y, num.trees = ~500, num.threads = 1, verbose = FALSE, seed = sample.int(10^5, 1), probability = TRUE)
Type: Probability estimation
Number of trees: 500
Sample size: 313
Number of independent variables: 8
Mtry: 2
Target node size: 10
Variable importance mode: none
Splitrule: gini
OOB prediction error (Brier s.): 0.1494135
Le modèle est ajusté. Maintenant, nous l’expliquons — d’abord globalement, puis un patient à la fois.
Calculer les valeurs SHAP avec kernelshap
SHAP a besoin de trois choses : le modèle ajusté, les lignes que vous voulez expliquer, et un jeu de données d’arrière-plan (un échantillon de référence que SHAP utilise pour demander « que prédirait le modèle si cette variable était absente ? » — il fait la moyenne des prédictions sur l’arrière-plan pour répondre). kernelshap est indépendant du modèle : vous lui passez une fonction de prédiction et il fonctionne sur n’importe quoi.
Pour un classifieur, nous expliquons la probabilité prédite de la classe positive, donc la fonction de prédiction renvoie .pred_pos. Nous expliquons un échantillon de patients du jeu de test, avec un arrière-plan de 50 lignes tiré de l’ensemble d’entraînement :
library(rsample)library(recipes)library(parsnip)library(workflows)library(kernelshap)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)test_data <-testing(split)rf_spec <-rand_forest(trees =500) |>set_engine("ranger") |>set_mode("classification")rf_wf <-workflow() |>add_recipe(recipe(diabetes ~ ., data = train_data)) |>add_model(rf_spec)set.seed(123)rf_fit <-fit(rf_wf, data = train_data)# Predict the PROBABILITY of the positive class (that is what we explain)pred_pos <-function(object, newdata) {predict(object, newdata, type ="prob")$.pred_pos}# Predictor columns only (drop the outcome)feature_cols <-setdiff(names(train_data), "diabetes")explain_rows <- test_data[1:30, feature_cols] # 30 patients to explain# Background sample: a reference set SHAP integrates over (50 rows is plenty here)set.seed(123)bg <- train_data[sample(nrow(train_data), 50), feature_cols]# Model-agnostic SHAP — works on ANY fitted model via the prediction functionset.seed(123)shap <-kernelshap(rf_fit, X = explain_rows, bg_X = bg, pred_fun = pred_pos, verbose =FALSE)shap
SHAP values of first observations:
pregnant glucose pressure triceps insulin mass
[1,] -0.003711544 -0.08540320 0.05633513 0.02357860 -0.08121159 0.025845210
[2,] -0.012035925 -0.02575099 0.03697462 0.06893323 0.06704444 0.004355229
pedigree age
[1,] -0.03438128 0.02651478
[2,] 0.03301961 -0.05928600
kernelshap() renvoie une valeur SHAP pour chaque variable × chaque ligne expliquée — une matrice complète de contributions signées, plus une valeur de référence unique (la probabilité prédite moyenne sur l’arrière-plan). L’affichage rapporte la valeur de référence et confirme la vérification additive : pour chaque ligne, valeur de référence + valeurs SHAP reconstruisent exactement la prédiction du modèle. Pour tracer, nous enveloppons le résultat dans un objet shapviz une fois et le réutilisons :
library(shapviz)sv <-shapviz(shap)# The base value = the model's average predicted probability over the backgroundget_baseline(sv)
[1] 0.3328291
La valeur de base ≈ 0.33 est la probabilité prédite moyenne de diabète du modèle sur l’arrière-plan — à peu près le taux de positifs des données. Chaque explication se lit relativement à cette valeur de référence : les valeurs SHAP d’un patient indiquent de combien, et dans quelle direction, chaque variable l’a éloigné de cette moyenne.
La vue globale : le beeswarm SHAP
La figure SHAP emblématique est le graphique en essaim d’abeilles (beeswarm, ou récapitulatif). Elle condense toute l’explication en une seule image : une ligne par variable, triée par importance (mean |SHAP|, en haut = la plus importante) ; un point par patient ; la position horizontale du point est la valeur SHAP de cette variable pour ce patient (gauche = a poussé la prédiction vers le négatif, droite = vers le positif) ; et la couleur du point est la valeur de la variable (basse = bleu, haute = rose). Elle montre l’importance, la direction et la relation valeur–effet, le tout à la fois.
Lisez-le de haut en bas.glucose se situe en haut — la variable la plus importante — et son schéma est un cas d’école : les patients à glucose élevé (rose) ont des valeurs SHAP positives (points loin à droite, poussant la prédiction vers le diabète), tandis que les patients à glucose bas (bleu) ont des valeurs négatives (poussant à l’écart). Le net gradient de couleur de gauche à droite indique que l’effet est monotone : plus de glucose, plus de risque prédit — exactement le récit clinique. mass (IMC), age et insulin suivent avec la même direction et une dispersion plus resserrée ; les prédicteurs restants contribuent moins. Ce graphique unique est l’explication globale du modèle — et chaque point qu’il contient est la contribution locale d’un patient réel, ce qui est le pont vers la vue locale.
NoteBeeswarm vs une simple barre d’importance
Si vous ne voulez que le classement, sv_importance(sv, kind = "bar") réduit chaque variable à une seule barre de mean |SHAP| — un diagramme d’importance épuré. Le beeswarm conserve la distribution : il montre non seulement à quel point une variable compte, mais aussi dans quelle direction les valeurs hautes et basses poussent, et si l’effet est cohérent d’un patient à l’autre. Cette information supplémentaire est la raison pour laquelle le beeswarm est la figure emblématique de SHAP.
Un diagramme en barres des magnitudes moyennes rend le classement sans ambiguïté :
library(shapviz)sv_importance(sv, kind ="bar", fill ="#3a86d4")
La version en barres dit la même chose que l’ordre vertical du beeswarm — glucose domine, puis mass, age, insulin — mais sous la forme d’un classement d’importance épuré que vous pouvez insérer dans un rapport. Le beeswarm ajoute la direction et la dispersion que la barre laisse de côté.
La vue locale : expliquer une prédiction
Voici ce que SHAP fait et qu’une barre d’importance par permutation ne peut pas faire : expliquer une prédiction spécifique. Nous prenons le premier patient du jeu de test et demandons pourquoi le modèle lui a attribué la probabilité qu’il a attribuée. Le graphique en cascade est la façon la plus claire de le voir — il part de la valeur de base et empile la contribution SHAP de chaque variable (rouge poussant vers le haut vers le positif, bleu poussant vers le bas vers le négatif) jusqu’à atterrir sur la prédiction du modèle pour ce patient :
library(shapviz)sv_waterfall(sv, row_id =1)
Lisez-le de bas en haut. La barre part de la valeur de base (≈ 0.33) — ce que le modèle prédit en moyenne. Puis chaque variable ajoute sa contribution : le glucose bas de ce patient est la grosse barre bleue qui pousse la prédiction vers le bas (à l’écart du diabète), avec insulin et la fonction pedigree qui poussent plus bas encore, tandis que l’age la pousse légèrement vers le haut. Les contributions s’empilent jusqu’à la prédiction finale du modèle pour ce patient — une probabilité en dessous de la valeur de référence (≈ 0.26), donc le modèle penche vers un verdict négatif. Nous pouvons vérifier la propriété additive exactement : valeur de base + valeurs SHAP de cette ligne = la prédiction.
library(shapviz)# The additive property: base value + the row's SHAP contributions = the predictionbase <-get_baseline(sv)row1 <-get_shap_values(sv)[1, ]recon <- base +sum(row1)c(base_value = base, sum_shap =sum(row1), reconstructed_prediction = recon)
Cette reconstructed_prediction est exactement la probabilité prédite du modèle pour le patient 1 — l’ explication n’est pas une approximation qui rend compte « à peu près » de la prédiction ; elle reconstruit le nombre à la décimale près. C’est la garantie additive, et c’est ce qui rend SHAP digne de confiance : il n’y a aucun reste inexpliqué.
Le graphique en force est la même explication locale dessinée horizontalement — les variables poussant à droite (vers le positif) et à gauche (vers le négatif) se rejoignant à la prédiction. Certains publics le trouvent plus intuitif :
library(shapviz)sv_force(sv, row_id =1)
Même information, forme différente : les forces bleues (glucose bas, insuline basse) poussant la prédiction vers le bas dominent la petite poussée rouge de l’âge, atterrissant en dessous de la valeur de référence. C’est l’avantage décisif — vous pouvez remettre à un clinicien cette image pour ce patient et dire exactement quelles mesures ont déterminé le verdict, de façon exécutable, reproductible. Un chatbot générique peut décrire SHAP ; il ne peut pas exécuter votre modèle sur votre patient et prouver le nombre.
Une voie alternative : DALEX
kernelshap + shapviz est la voie rapide et moderne, mais vous rencontrerez aussi SHAP via DALEX, dont predict_parts(type = "shap") calcule les mêmes attributions de Shapley en faisant la moyenne des contributions des variables sur de nombreux ordonnancements aléatoires. Cela vaut la peine de le connaître car DALEX est une boîte à outils d’explicabilité complète (il fait aussi de l’importance par permutation et de la dépendance partielle). On enveloppe d’abord le modèle dans un explainer DALEX, puis on explique une observation :
library(rsample)library(recipes)library(parsnip)library(workflows)library(DALEX)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)test_data <-testing(split)rf_spec <-rand_forest(trees =500) |>set_engine("ranger") |>set_mode("classification")rf_wf <-workflow() |>add_recipe(recipe(diabetes ~ ., data = train_data)) |>add_model(rf_spec)set.seed(123)rf_fit <-fit(rf_wf, data = train_data)feature_cols <-setdiff(names(train_data), "diabetes")# A DALEX explainer wraps the model + data + a probability prediction functionexplainer <-explain( rf_fit,data = train_data[feature_cols],y =as.numeric(train_data$diabetes =="pos"),predict_function =function(m, newdata) predict(m, newdata, type ="prob")$.pred_pos,label ="random forest",verbose =FALSE)# SHAP for the same first test patient (B = 25 random orderings, averaged)set.seed(123)shap_dalex <-predict_parts(explainer,new_observation = test_data[1, feature_cols],type ="shap", B =25)plot(shap_dalex)
Le break-down DALEX raconte la même histoire que la cascade kernelshap — glucose et insulin poussent la probabilité prédite de ce patient vers le bas, age la pousse vers le haut — calculée par un algorithme différent (en faisant la moyenne sur des ordonnancements aléatoires des variables plutôt que par la pondération du noyau). Lorsque deux implémentations SHAP indépendantes s’accordent, vous pouvez faire confiance à l’explication. Utilisez celle qui convient à votre pile ; shapviz donne le beeswarm global le plus soigné, DALEX donne une boîte à outils d’explicabilité plus complète.
NoteLes valeurs de Shapley, l’idée (optionnel)
SHAP repose sur la valeur de Shapley issue de la théorie des jeux coopératifs. Pensez aux variables comme à des joueurs dans un jeu dont le « gain » est la distance de la prédiction par rapport à la prédiction moyenne. La valeur de Shapley demande : comment devrions-nous répartir équitablement ce gain entre les joueurs ?
La part équitable de la variable \(j\) est sa contribution marginale moyenne sur chaque coalition possible des autres variables. Notez \(f(S)\) la prédiction attendue du modèle lorsque seules les variables du sous-ensemble \(S\) sont « connues » (les autres étant moyennées sur les données). Ajouter la variable \(j\) à une coalition \(S\) change la prédiction de \(f(S \cup \{j\}) - f(S)\). La valeur de Shapley \(\phi_j\) fait la moyenne de cette contribution marginale sur tous les sous-ensembles \(S\) qui ne contiennent pas déjà \(j\), pondérée de sorte que chaque taille de coalition compte de façon égale :
où \(F\) est l’ensemble complet des variables. C’est l’attribution unique qui satisfait quatre axiomes d’équité : l’efficacité (les contributions s’additionnent pour combler l’écart entre la prédiction et la moyenne — l’additivité), la symétrie (deux variables qui contribuent toujours de façon égale reçoivent un crédit égal), le dummy (une variable qui ne change jamais la prédiction reçoit zéro), et la linéarité. L’axiome d’efficacité est précisément la propriété additive que nous avons vérifiée ci-dessus :
avec \(\phi_0\) la valeur de base (la prédiction moyenne). Calculer la somme exactement est exponentiel en le nombre de variables, donc les méthodes pratiques l’approximent : Kernel SHAP (utilisé par kernelshap) la reformule comme un problème de moindres carrés astucieusement pondéré ; Tree SHAP la calcule exactement et rapidement pour les ensembles d’arbres ; DALEX fait la moyenne sur des ordonnancements aléatoires. Toutes visent le même \(\phi_j\) — l’attribution équitable et additive.
🟢 Avec un agent IA
Vous avez un modèle et une prédiction à justifier ? Demandez à Prova« calcule les valeurs SHAP pour mon modèle ajusté et montre-moi pourquoi il a prédit cela pour cette ligne » — elle répond avec du code kernelshap + shapviz (ou DALEX) que vous exécutez sur votre propre modèle et vos propres données, puis vous aide à lire le beeswarm, la cascade, et la vérification additive. The runtime is the judge.Ask Prova →
Problèmes courants
SHAP est lent sur un grand jeu de données.kernelshap évalue le modèle de nombreuses fois par ligne expliquée. N’expliquez pas le jeu de données entier — expliquez un échantillon de lignes (X = test_data[1:30, ]) et utilisez un petit ensemble d’arrière-plan (30 à 100 lignes suffisent généralement). Pour les modèles à arbres, le Tree SHAP dédié dans shapviz::shapviz() (passez directement le modèle xgboost/ranger ajusté) est bien plus rapide que la méthode du noyau indépendante du modèle.
La fonction de prédiction renvoie la mauvaise chose. Pour un classifieur, vous voulez presque toujours expliquer une probabilité, pas la classe prédite. Faites en sorte que pred_fun renvoie la probabilité de la classe positive (predict(object, newdata, type = "prob")$.pred_pos), sinon vous obtiendrez des valeurs SHAP pour une étiquette 0/1 difficiles à lire.
Valeur de base + valeurs SHAP n’égalent pas la prédiction. Elles le doivent (c’est la garantie additive) — un désaccord signifie que votre fonction de prédiction et la quantité expliquée divergent (par ex. vous avez calculé SHAP sur des probabilités mais vérifié par rapport aux log-odds, ou l’ensemble d’arrière-plan ne correspond pas à la distribution d’entraînement). Confirmez que get_baseline(sv) + sum(get_shap_values(sv)[i, ]) reconstruit la ligne i.
Les couleurs du beeswarm semblent aléatoires / non informatives. Cela signifie que la valeur de la variable et sa contribution SHAP ne sont pas liées de façon monotone — ce qui est une vraie information, pas un bug (le modèle utilise cette variable de façon non monotone). Pour la forme de la relation, tracez des courbes de dépendance partielle & ICE.
Questions fréquentes
NoteComment calculer les valeurs SHAP en R ?
Ajustez n’importe quel modèle, puis utilisez kernelshap (indépendant du modèle) suivi de shapviz pour tracer. Définissez une fonction de prédiction qui renvoie la quantité à expliquer (pour un classifieur, la probabilité de la classe positive), appelez kernelshap(model, X = rows_to_explain, bg_X = background, pred_fun = ...), enveloppez le résultat avec shapviz(), puis tracez sv_importance(sv, kind = "beeswarm") pour la vue globale et sv_waterfall(sv, row_id = 1) pour une prédiction. DALEX::predict_parts(type = "shap") est une voie équivalente.
NoteQue sont les valeurs SHAP et que vous disent-elles ?
Une valeur SHAP est la contribution signée d’une seule variable à une seule prédiction : de combien, et dans quelle direction, cette variable a éloigné la prédiction de la sortie moyenne du modèle (la valeur de base). Additionnez les valeurs SHAP d’une ligne et ajoutez la valeur de base et vous obtenez la prédiction exactement (la propriété additive). Faites la moyenne des magnitudes sur de nombreuses lignes (mean |SHAP|) et vous obtenez un classement d’importance global. Ainsi, SHAP explique à la fois une prédiction et le modèle entier avec les mêmes nombres.
NoteQuelle est la différence entre SHAP et l’importance des variables ?
L’importance des variables simple (par ex. l’importance par permutation) donne un classement global — quelles variables comptent pour le modèle dans l’ensemble — et rien sur les prédictions individuelles. SHAP donne ce classement global aussi (moyenne de |SHAP|), mais aussi une explication locale pour chaque prédiction unique, avec la direction de l’effet de chaque variable et une décomposition additive exacte. SHAP est l’outil le plus complet (et le plus coûteux) ; l’importance par permutation est le rapide, limité au global.
NoteQuel package R utiliser pour les valeurs de Shapley en R ?
Pour la plupart des workflows, kernelshap (pour calculer) plus shapviz (pour visualiser) est la combinaison moderne et rapide — shapviz fait aussi du Tree SHAP exact et rapide lorsque vous passez directement un modèle xgboost/lightgbm/ ranger. DALEX calcule SHAP via predict_parts(type = "shap") et regroupe une boîte à outils d’explicabilité complète (importance par permutation, dépendance partielle). Les packages plus anciens fastshap et iml calculent aussi SHAP. Ils visent tous les mêmes attributions de Shapley ; choisissez selon ce qui est déjà dans votre pile.
NoteSHAP est-il indépendant du modèle — fonctionne-t-il sur xgboost, la forêt aléatoire et d’autres ?
Oui. Kernel SHAP (dans kernelshap) est indépendant du modèle : donnez-lui une fonction de prédiction et il explique n’importe quel modèle ajusté — forêt aléatoire, xgboost, SVM, un réseau de neurones. Pour les ensembles d’arbres spécifiquement, il existe aussi Tree SHAP, un algorithme exact et bien plus rapide (shapviz() l’utilise automatiquement lorsque vous passez un modèle à arbres pris en charge). L’explication — valeur de base + contributions additives des variables — est la même quel que soit le modèle.
Testez vos connaissances
ImportantExercice : expliquer un patient à haut risque
Dans la leçon, nous avons expliqué le premier patient du jeu de test (un cas à faible probabilité, vraisemblablement négatif). Maintenant trouvez le patient du jeu de test dont le modèle est le plus confiant qu’il est positif et expliquez cette prédiction. En utilisant le rf_fit ajusté et l’objet shap de la leçon (qui explique test_data[1:30, ]), identifiez lequel de ces 30 patients a la probabilité prédite de diabète la plus élevée, tracez sa cascade, et dites quelles variables ont poussé la prédiction vers le haut.
AstuceIndice
Les probabilités prédites proviennent de predict(rf_fit, test_data[1:30, ], type = "prob")$.pred_pos. La ligne avec le maximum est which.max(...). Passez cet indice à sv_waterfall(sv, row_id = ...). Pour un patient à haut risque, attendez-vous à ce qu’un glucose élevé (et vraisemblablement un mass/age élevé) contribue de grandes barres positives (rouges) poussant la prédiction vers le haut.
AstuceSolution
library(shapviz)# Predicted positive-class probability for the 30 explained patientsfeature_cols <-setdiff(names(test_data), "diabetes")probs <-predict(rf_fit, test_data[1:30, feature_cols], type ="prob")$.pred_poshigh_id <-which.max(probs) # the most confidently-positive patientc(row = high_id, probability = probs[high_id])# Their single-prediction explanationsv_waterfall(sv, row_id = high_id)
Pour le patient à plus haut risque, la cascade est l’image miroir du patient 1 : elle part de la même valeur de base (≈ 0.33) mais un glucose élevé contribue désormais une grande barre positive (rouge) poussant la prédiction vers le haut, rejointe par un mass et un age élevés, atterrissant sur une probabilité bien au-dessus de la valeur de référence. Même modèle, même valeur de base — histoire opposée, parce que les valeurs des variables sont différentes. C’est exactement pourquoi les explications locales comptent : l’importance est globale, mais la raison est propre à chaque patient.
Vérification rapide. Vous calculez SHAP pour un patient et les contributions des variables sont glucose = +0.18, mass = +0.06, age = +0.03, et tout le reste s’additionne à -0.02. La valeur de base est 0.33. Quelle probabilité le modèle a-t-il prédite pour ce patient, et le classeriez-vous positif ou négatif à un seuil de 0.5 ?
NoteAfficher la réponse
Utilisez la propriété additive : prédiction = valeur de base + somme des valeurs SHAP = 0.33 + 0.18 + 0.06 + 0.03 − 0.02 = 0.58. Le modèle a prédit une probabilité de diabète de 0.58 — au-dessus du seuil de 0.5, donc ce patient est classé positif. L’explication vous dit aussi pourquoi : glucose (+0.18) a fait l’essentiel du travail, avec mass et age ajoutant de plus petites poussées positives. (Savoir si 0.5 est le bon seuil est une question distincte — voir la série sur la classification.)
Conclusion
Vous avez expliqué un modèle de deux façons avec SHAP sur les données PimaIndiansDiabetes2. Le beeswarm global a résumé quelles variables pilotent la forêt aléatoire — glucose, puis mass, age et insulin — et a montré comment (les valeurs hautes poussant le risque vers le haut). Les graphiques en cascade et en force locaux ont expliqué un patient spécifique, et la vérification additive a prouvé que l’explication reconstruit la prédiction exactement : valeur de base + contributions SHAP = la probabilité prédite, sans reste. Vous avez calculé SHAP de manière indépendante du modèle avec kernelshap + shapviz, l’avez confirmé par rapport à DALEX, et vu l’idée de théorie des jeux qui la sous-tend. La règle pratique : expliquez un échantillon de lignes sur un petit arrière-plan, lisez le beeswarm pour le modèle et la cascade pour le cas, et vérifiez toujours que les contributions s’additionnent. C’est l’avantage décisif — un pourquoi exécutable et vérifiable pour n’importe quelle prédiction.
Importance des variables — importance indépendante du modèle et par permutation ; la contrepartie limitée au global que SHAP généralise. · Dépendance partielle & ICE — la forme de l’effet d’une variable, que SHAP résume mais ne dessine pas.
Prouvez que vous savez le faire. Maîtrisez toute la série Explicabilité des modèles en R — suivez votre parcours, construisez des projets et obtenez un certificat.
Cette leçon est reproductible : chaque valeur SHAP, chaque classement et chaque 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
Lundberg, S. M., & Lee, S.-I. (2017). A Unified Approach to Interpreting Model Predictions. Advances in Neural Information Processing Systems (NeurIPS) 30. (Le cadre SHAP.)
Shapley, L. S. (1953). A Value for n-Person Games. In Contributions to the Theory of Games II. Princeton University Press. (La valeur de Shapley originale.)
Molnar, C. (2022). Interpretable Machine Learning: A Guide for Making Black Box Models Explainable (2nd ed.). Free online. (SHAP, valeurs de Shapley, explications globales et locales.)
Biecek, P., & Burzykowski, T. (2021). Explanatory Model Analysis. CRC Press / free online. (La boîte à outils DALEX et les explications break-down / SHAP.)
Mayer, M. kernelshap and shapviz package documentation. (Kernel/permutation SHAP and SHAP visualizations in R.)
@online{2026,
author = {},
title = {Valeurs SHAP en R : expliquer les prédictions d’un modèle},
date = {2026-06-25},
url = {https://www.datanovia.com/learn/machine-learning/explainability/shap-values},
langid = {fr}
}