SHAP et LIME : Guide Complet IA Explicable

SHAP et LIME : Guide Complet — IA Explicable

SHAP et LIME expliquent le comportement d’un modèle à partir de ses prédictions. Ils aident à examiner le rôle des variables, mais une explication lisible ne suffit pas à prouver que le modèle a raison. Ce guide compare les deux approches sur une même forêt aléatoire, une même observation et une même sortie numérique.

Vous allez vérifier la somme des contributions SHAP, mesurer l’écart entre LIME et le modèle, puis repérer les situations où l’explication mérite d’être remise en question. Le code, le graphique et les contrôles sont disponibles gratuitement. Les données sont entièrement synthétiques.

SHAP : répartir une différence par rapport à une référence

SHAP signifie SHapley Additive exPlanations. Pour une observation x, l’explication additive prend la forme f(x) = référence + φ₁ + … + φₚ. Chaque φ indique une contribution, positive ou négative, dans l’espace de sortie expliqué. Le cadre est présenté dans l’article de Lundberg et Lee.

La référence compte autant que les barres du graphique. Dire « volume contribue à hauteur de +4,66 » n’a de sens qu’en précisant le modèle, l’observation, la référence et l’unité de sortie. Cela ne signifie pas qu’augmenter le volume d’une unité ferait augmenter le résultat réel de 4,66.

Que calcule une coalition de variables ?

Une valeur de Shapley moyenne la contribution marginale d’une variable dans plusieurs coalitions. Pour le calcul interventional utilisé ici, nous gardons les variables de la coalition à leurs valeurs dans x, complétons les autres avec des lignes du jeu de référence et moyennons les prédictions du même modèle déjà entraîné. Nous ne réentraînons pas une forêt différente pour chaque sous-ensemble.

Dans cet exemple à quatre variables, le fichier de vérification peut énumérer les seize coalitions et comparer directement ce calcul à Tree SHAP. Cette vérification indépendante serait beaucoup plus coûteuse avec de nombreuses colonnes.

Quel explainer utiliser ?

TreeExplainer exploite la structure des modèles à arbres. Nous fixons feature_perturbation="interventional" et fournissons explicitement un jeu de référence de 80 lignes d’apprentissage. model_output="raw" correspond ici à la prédiction numérique du régresseur. Pour d’autres familles de modèles, il faut choisir un explainer adapté et vérifier ses hypothèses et son coût.

LIME : apprendre un modèle simple autour du cas étudié

LIME signifie Local Interpretable Model-agnostic Explanations. Il génère des versions perturbées d’une observation, interroge le modèle et ajuste un modèle interprétable pondéré par proximité. L’objectif est d’imiter localement la fonction de prédiction. Le papier de Ribeiro, Singh et Guestrin présente cette démarche.

Dans notre exemple tabulaire, les variables continues sont discrétisées en intervalles. Une condition comme -0.04 < volume <= 0.60 décrit un intervalle associé au cas expliqué. Son coefficient appartient au modèle substitut de LIME ; ce n’est pas une valeur SHAP ni une pente générale valable pour tout le tableau.

Deux diagnostics doivent accompagner cette explication : l’écart entre la prédiction du substitut et celle de la forêt au point étudié, et le R² pondéré du substitut sur les perturbations. La documentation de LIME décrit les paramètres et les sorties utilisés. Une graine fixe rend l’expérience reproductible, mais ne garantit pas une bonne approximation.

SHAP ou LIME : que compare-t-on ?

Question SHAP dans cet exemple LIME dans cet exemple
Ce qui est calculé Contributions par rapport à un jeu de référence explicite. Coefficients d’un substitut local sur des conditions d’intervalles.
Contrôle principal Référence + contributions ≈ prédiction de la forêt. Écart au point étudié et fidélité sur les perturbations.
Choix à documenter Sortie expliquée, observations de référence, traitement des dépendances. Perturbations, discrétisation, noyau de proximité, nombre d’échantillons et graine.
Conclusion à éviter Une somme correcte prouve que la prédiction est juste. Un tableau de coefficients prouve que le substitut est fidèle.

Exemple Python complet : expliquer un score synthétique

Nous créons 800 lignes et quatre colonnes sans unité, nommées volume, complexite, charge et bruit. La cible artificielle combine les trois premières, une interaction et du bruit aléatoire. Ces noms sont pédagogiques : le tableau ne représente ni des utilisateurs, ni une activité réelle.

La forêt est ajustée sur 600 lignes ; 200 restent réservées. Nous expliquons la première ligne du test, choisie avant d’examiner ses résultats. Le jeu de référence SHAP et les statistiques utilisées par LIME viennent uniquement de l’apprentissage. Aucun réglage du modèle n’est sélectionné sur les résultats du test.

Versions exécutées sous Windows : Python 3.12.14, NumPy 2.5.3, scikit-learn 1.9.1, SHAP 0.52.0 et LIME 0.2.0.1. Matplotlib 3.11.2 génère la figure. Les dépendances directes et un relevé complet de l’environnement sont inclus.

Télécharger le code SHAP/LIME, le graphique à générer et les dix contrôles (ZIP gratuit). Aucun compte nécessaire. Dans un environnement Python dédié, exécutez :

python -m pip install -r requirements.txt
python exemple_shap_lime.py
python verifier_exemple.py
python figure_shap_lime.py
import numpy as np
import shap
from lime.lime_tabular import LimeTabularExplainer
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import root_mean_squared_error
from sklearn.model_selection import train_test_split

# Données artificielles : trois signaux et une variable sans effet direct.
# Les colonnes sont sans unité ; la cible est un score synthétique.
rng = np.random.default_rng(42)
noms = ["volume", "complexite", "charge", "bruit"]
X = rng.normal(size=(800, 4))
y = (50 + 10 * X[:, 0] + 6 * X[:, 1]
     + 4 * X[:, 0] * X[:, 2]
     + 3 * np.maximum(X[:, 2], 0) ** 2 + rng.normal(size=800))
idx_train, idx_test = train_test_split(
    np.arange(len(X)), test_size=0.25, random_state=42
)
X_train, X_test = X[idx_train], X[idx_test]
y_train, y_test = y[idx_train], y[idx_test]
modele = RandomForestRegressor(
    n_estimators=120, max_depth=6, min_samples_leaf=3,
    random_state=42, n_jobs=1,
).fit(X_train, y_train)
pred_test = modele.predict(X_test)

# Premier cas réservé, choisi avant de regarder son explication.
x = X_test[0:1]
prediction = float(modele.predict(x)[0])
fond_indices = np.random.default_rng(7).choice(len(X_train), 80, replace=False)
fond = X_train[fond_indices]
exp_shap = shap.TreeExplainer(
    modele, data=fond, feature_perturbation="interventional",
    model_output="raw", feature_names=noms,
)
attributions = exp_shap(x)
base = float(attributions.base_values[0])
contributions = attributions.values[0]
reconstruction = base + float(contributions.sum())

# Une nouvelle instance d'explainer remet le générateur à la graine voulue.
def expliquer_lime(graine=42):
    explainer = LimeTabularExplainer(
        X_train, feature_names=noms, mode="regression",
        discretize_continuous=True, random_state=graine,
        feature_selection="none",
    )
    return explainer.explain_instance(
        x[0], modele.predict, num_features=len(noms), num_samples=5000
    )

exp_lime = expliquer_lime()
approximation = float(np.asarray(exp_lime.local_pred).item())
print(f"Apprentissage : {len(X_train)} ; test : {len(X_test)}")
print(f"RMSE sur le test : {root_mean_squared_error(y_test, pred_test):.4f}")
print(f"Valeur observée du premier cas : {y_test[0]:.4f}")
print(f"Prédiction de la forêt : {prediction:.4f}")
print(f"Référence SHAP : {base:.4f}")
for nom, valeur in zip(noms, contributions):
    print(f"SHAP {nom} : {valeur:+.4f}")
print(f"Référence + contributions SHAP : {reconstruction:.4f}")
print(f"Écart d'additivité SHAP : {abs(prediction - reconstruction):.2e}")
print(f"Prédiction du substitut LIME : {approximation:.4f}")
print(f"Écart local LIME / forêt : {abs(approximation - prediction):.4f}")
print(f"R² pondéré du substitut sur les perturbations : {exp_lime.score:.4f}")
print("Coefficients LIME des conditions (pas des valeurs SHAP) :")
for condition, coefficient in exp_lime.as_list():
    print(f"  {condition} : {coefficient:+.4f}")

Résultats : une somme correcte et une approximation peu fidèle

Voici la sortie de l’exécution vérifiée. Les dernières décimales peuvent varier selon l’environnement numérique :

Apprentissage : 600 ; test : 200
RMSE sur le test : 3.2305
Valeur observée du premier cas : 53.0634
Prédiction de la forêt : 54.0366
Référence SHAP : 50.0994
SHAP volume : +4.6641
SHAP complexite : +0.6354
SHAP charge : -1.3673
SHAP bruit : +0.0050
Référence + contributions SHAP : 54.0366
Écart d'additivité SHAP : 1.05e-07
Prédiction du substitut LIME : 55.6957
Écart local LIME / forêt : 1.6592
R² pondéré du substitut sur les perturbations : 0.0571
Coefficients LIME des conditions (pas des valeurs SHAP) :
  -0.04 < volume <= 0.60 : +4.5931
  0.01 < complexite <= 0.65 : +3.8008
  -0.01 < charge <= 0.66 : -1.3032
  -0.75 < bruit <= -0.03 : -0.3699
Pour une observation synthétique, SHAP reconstitue le score de la forêt à 54,04 ; LIME donne 55,70 et la cible observée vaut 53,06.
À gauche : contributions SHAP en points du score par rapport à la référence 50,10. À droite : cible observée, prédiction du modèle, reconstruction SHAP et substitut LIME. Le graphique ne compare pas des importances de variables interchangeables. Cliquez pour agrandir.

La somme SHAP explique le modèle, pas son erreur

La forêt prédit 54,0366 pour une cible observée de 53,0634. La référence SHAP vaut 50,0994. En ajoutant les quatre contributions, on retrouve 54,0366 à environ 10−7 près. Le calcul indépendant des seize coalitions retrouve aussi les valeurs de Tree SHAP.

Ce résultat valide la décomposition pour ce protocole. Il ne fait pas disparaître l’écart entre la prédiction et la cible. La RMSE sur les 200 observations réservées vaut 3,2305 points du score synthétique ; c’est une mesure distincte de l’additivité.

La variable bruit n’intervient pas dans la formule de génération de la cible, mais sa contribution SHAP est légèrement non nulle. L’explication décrit ce que la forêt ajustée a appris, avec un échantillon fini. Elle n’est pas une restitution parfaite de la formule qui a produit les données.

LIME : ne pas cacher une faible fidélité

Le substitut prédit 55,6957, soit un écart de 1,6592 points avec la forêt. Son R² pondéré n’est que de 0,0571 sur les perturbations. Avec ces réglages, il reproduit mal la variation de la forêt dans le voisinage généré. Ses coefficients ne constituent donc pas une explication locale suffisamment fidèle à accepter sans examen.

Ce R² concerne l’ajustement du substitut sur les perturbations utilisées pour l’entraîner. Ce n’est ni le R² de la forêt sur le test, ni une validation indépendante de l’explication. Il ne faut pas le présenter comme une précision de 5,71 %.

Le vérificateur répète LIME avec cinq graines fixées à l’avance : 1, 7, 21, 42 et 99. Les prédictions locales vont de 55,6957 à 56,3569 ; les R² pondérés restent entre 0,0456 et 0,0594. Changer seulement la graine ne résout pas ici le problème. Ce petit essai ne classe pas SHAP et LIME de manière générale.

Pour poursuivre l’analyse, examinez la discrétisation, la largeur du noyau, les perturbations plausibles et le nombre d’échantillons. Définissez le protocole sur des cas de validation et comparez plusieurs observations. Ne conservez pas uniquement l’explication qui raconte l’histoire attendue.

Les erreurs d’interprétation à éviter

Confondre probabilités, scores et log-odds

Ici, toutes les contributions SHAP sont exprimées dans l’unité du score de régression. En classification, vérifiez la sortie réellement expliquée et la classe sélectionnée. Avec certains modèles, une sortie brute correspond à des log-odds. Une contribution de +0,3 dans cet espace n’est pas une hausse de 30 points de probabilité. La forme des tableaux peut également dépendre du nombre de sorties : ne recopiez pas une indexation sans la contrôler.

Attribuer une cause réelle à une barre positive

Une explication du prédicteur ne prouve pas l’effet d’une intervention dans le monde réel. Des variables corrélées, des informations absentes ou des biais de collecte peuvent changer l’interprétation. Le guide SHAP consacré aux interprétations causales détaille cette distinction. Le nom interventional d’un paramètre ne suffit pas à transformer l’expérience en étude causale.

Oublier le jeu de référence et les dépendances

Une autre population de référence peut modifier la base et les contributions sans changer la prédiction à expliquer. L’exemple officiel sur une fonction OR illustre ce mécanisme. Documentez le choix du fond. Avec des colonnes dépendantes, les combinaisons créées par le masquage ou les perturbations peuvent aussi être peu plausibles.

Passer d’un cas local à une importance générale

La barre volume domine pour notre première observation. Cela ne suffit pas à conclure qu’elle domine pour tous les cas. Une synthèse sur plusieurs observations doit préciser leur sélection, la sortie expliquée et la façon d’agréger les valeurs. Une moyenne de valeurs absolues masque notamment le sens des contributions.

Expliquer une version différente du modèle

Sur vos données, faites traverser aux lignes perturbées le même traitement que celui utilisé en production. Vérifiez l’ordre des colonnes, les transformations et les catégories. Si une pipeline prédit à partir de données brutes, sa fonction de prédiction doit être appelée de façon cohérente ; expliquer une matrice transformée demande de nommer les variables transformées.

Trois questions pour vérifier la lecture

Une somme SHAP correcte garantit-elle une bonne prédiction ?

Non. Elle vérifie la décomposition de la sortie expliquée. Ici, SHAP retrouve 54,0366 alors que la cible observée vaut 53,0634. L’erreur du modèle se mesure séparément.

Puis-je comparer directement les quatre coefficients LIME aux quatre valeurs SHAP ?

Pas comme des quantités équivalentes. Ici, LIME attribue des coefficients à des conditions d’intervalles dans son substitut. SHAP répartit l’écart à une référence selon les coalitions du modèle fixé. Les deux affichages n’ont pas la même construction.

Faut-il retenir la graine LIME qui donne le meilleur résultat ?

Une graine sert à reproduire un essai. Retenir seulement celle qui produit une explication séduisante masque la variabilité. Documentez plusieurs graines fixées à l’avance et contrôlez aussi les choix de voisinage et de représentation.

Continuer le parcours Python

Guide révisé et exemple exécuté le 26 septembre 2026. Les chiffres décrivent les données synthétiques et les réglages présentés, sans performance réelle ou gain financier supposé.

Expérience : changer la référence sans changer la prédiction

Pour observer directement le rôle du fond, essayez le cas SHAP avec deux populations de référence et une même prédiction. La forêt et la ligne sont figées ; les contributions changent, et les deux décompositions sont vérifiées par les coalitions.

About Salah YAHIAOUI

Salah YAHIAOUI publie sur The Pingouin des tutoriels Python et des décryptages sur l’intelligence artificielle. Les cas pratiques récents précisent leurs données, leurs tests et leurs limites. À propos, méthode éditoriale et contact.

View all posts by Salah YAHIAOUI →