Shapley Additive Global Importance (SAGE) example#

In this example, we demonstrate how to measure feature importance using SAGE Covert et al.[1] on the diabetes dataset. Read more in the User Guide. For this example, we use the marginal version of SAGE, which limits the computational cost. To further reduce the computational cost, Shapley values are estimated using a Monte Carlo approximation. Only a subset of all possible feature coalitions is sampled. This is controlled by the n_subsets parameter. Finally, the expectation over the marginal distribution is also approximated using n_permutations.

LightGBM example on the bike sharing dataset#

We demonstrate how to use SAGE on the bike sharing dataset. We fit a LightGBM model and compute its \(R^2\) score on a held-out test set.

import numpy as np
from sklearn.datasets import fetch_openml
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.metrics import r2_score
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OrdinalEncoder

bike_sharing = fetch_openml("Bike_Sharing_Demand", version=2, as_frame=True)
df = bike_sharing.frame
df = df[df["year"] == 0].drop(columns=["year"])

X = df.drop(columns=["count"]).to_numpy()
X = OrdinalEncoder().fit_transform(X)
y = df["count"].to_numpy()
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
model = HistGradientBoostingRegressor(random_state=0, max_depth=5)
model.fit(X_train, y_train)
y_pred = model.predict(X_test)
print("R2 score:", r2_score(y_test, y_pred))
R2 score: 0.9283833661677658

SAGE feature importance#

We compute the SAGE feature importance for the fitted model. To keep the computational cost tractable, we use a subset of the test set to compute the SAGE values. Finally, the SAGE values are plotted using the plot_importance function.

import matplotlib.pyplot as plt

from hidimstat import SAGE

sage = SAGE(
    model,
    n_subsets=512,
    n_permutations=10,
    random_state=0,
    n_jobs=8,
)
sage.fit(X_train)
subsample_size = 1024
rng = np.random.default_rng(0)
subsample_ids = rng.choice(len(X_test), size=subsample_size, replace=False)
sage.importance(X_test[subsample_ids], y_test[subsample_ids])
ax = sage.plot_importance(
    feature_names=df.drop(columns=["count"]).columns.tolist(),
    color="tab:purple",
)
ax.semilogx()
plt.tight_layout()
plt.show()
plot msage
  0%|          | 0/1925 [00:00<?, ?it/s]
  1%|          | 16/1925 [00:04<09:46,  3.25it/s]
  1%|          | 24/1925 [00:05<06:32,  4.84it/s]
  2%|▏         | 32/1925 [00:05<04:29,  7.02it/s]
  2%|▏         | 40/1925 [00:05<03:14,  9.71it/s]
  2%|▏         | 48/1925 [00:06<02:25, 12.87it/s]
  3%|▎         | 56/1925 [00:06<01:56, 16.00it/s]
  3%|▎         | 64/1925 [00:06<01:37, 19.18it/s]
  4%|▎         | 72/1925 [00:06<01:19, 23.21it/s]
  4%|▍         | 80/1925 [00:07<01:09, 26.63it/s]
  5%|▍         | 88/1925 [00:07<01:03, 29.00it/s]
  5%|▍         | 96/1925 [00:07<00:59, 30.68it/s]
  5%|▌         | 104/1925 [00:07<00:57, 31.41it/s]
  6%|▌         | 112/1925 [00:07<00:56, 32.08it/s]
  6%|▌         | 120/1925 [00:08<00:54, 32.99it/s]
  7%|▋         | 128/1925 [00:08<00:52, 34.31it/s]
  7%|▋         | 136/1925 [00:08<00:53, 33.32it/s]
  7%|▋         | 144/1925 [00:08<00:53, 33.51it/s]
  8%|▊         | 152/1925 [00:09<00:48, 36.24it/s]
  8%|▊         | 160/1925 [00:09<00:48, 36.24it/s]
  9%|▊         | 168/1925 [00:09<00:48, 36.19it/s]
  9%|▉         | 176/1925 [00:09<00:47, 37.10it/s]
 10%|▉         | 184/1925 [00:09<00:46, 37.09it/s]
 10%|▉         | 192/1925 [00:10<00:46, 37.06it/s]
 10%|█         | 200/1925 [00:10<00:45, 37.69it/s]
 11%|█         | 208/1925 [00:10<00:45, 37.57it/s]
 11%|█         | 216/1925 [00:10<00:45, 37.45it/s]
 12%|█▏        | 224/1925 [00:11<00:49, 34.59it/s]
 12%|█▏        | 232/1925 [00:11<00:50, 33.28it/s]
 12%|█▏        | 240/1925 [00:11<00:47, 35.55it/s]
 13%|█▎        | 248/1925 [00:11<00:52, 31.90it/s]
 13%|█▎        | 256/1925 [00:11<00:47, 35.50it/s]
 14%|█▎        | 264/1925 [00:12<00:48, 34.45it/s]
 14%|█▍        | 272/1925 [00:12<00:49, 33.14it/s]
 15%|█▍        | 280/1925 [00:12<00:47, 34.98it/s]
 15%|█▍        | 288/1925 [00:12<00:49, 33.27it/s]
 15%|█▌        | 296/1925 [00:13<00:47, 34.59it/s]
 16%|█▌        | 304/1925 [00:13<00:47, 34.26it/s]
 16%|█▌        | 312/1925 [00:13<00:47, 34.21it/s]
 17%|█▋        | 320/1925 [00:13<00:45, 35.10it/s]
 17%|█▋        | 328/1925 [00:14<00:44, 35.52it/s]
 17%|█▋        | 336/1925 [00:14<00:45, 34.59it/s]
 18%|█▊        | 344/1925 [00:14<00:45, 34.62it/s]
 18%|█▊        | 352/1925 [00:14<00:45, 34.40it/s]
 19%|█▊        | 360/1925 [00:15<00:45, 34.12it/s]
 19%|█▉        | 368/1925 [00:15<00:43, 36.10it/s]
 20%|█▉        | 376/1925 [00:15<00:42, 36.17it/s]
 20%|█▉        | 384/1925 [00:15<00:42, 36.14it/s]
 20%|██        | 392/1925 [00:15<00:43, 35.31it/s]
 21%|██        | 400/1925 [00:16<00:41, 37.18it/s]
 21%|██        | 408/1925 [00:16<00:41, 36.22it/s]
 22%|██▏       | 416/1925 [00:16<00:40, 37.13it/s]
 22%|██▏       | 424/1925 [00:16<00:39, 38.17it/s]
 22%|██▏       | 432/1925 [00:16<00:38, 38.30it/s]
 23%|██▎       | 440/1925 [00:17<00:40, 37.00it/s]
 23%|██▎       | 448/1925 [00:17<00:42, 35.14it/s]
 24%|██▎       | 456/1925 [00:17<00:40, 36.43it/s]
 24%|██▍       | 464/1925 [00:17<00:39, 36.94it/s]
 25%|██▍       | 472/1925 [00:18<00:41, 35.30it/s]
 25%|██▍       | 480/1925 [00:18<00:41, 34.69it/s]
 25%|██▌       | 488/1925 [00:18<00:43, 33.12it/s]
 26%|██▌       | 496/1925 [00:18<00:41, 34.47it/s]
 26%|██▌       | 504/1925 [00:19<00:40, 34.77it/s]
 27%|██▋       | 512/1925 [00:19<00:40, 34.80it/s]
 27%|██▋       | 520/1925 [00:19<00:39, 35.30it/s]
 27%|██▋       | 528/1925 [00:19<00:42, 33.14it/s]
 28%|██▊       | 536/1925 [00:19<00:39, 35.49it/s]
 28%|██▊       | 544/1925 [00:20<00:37, 36.38it/s]
 29%|██▊       | 552/1925 [00:20<00:40, 33.71it/s]
 29%|██▉       | 560/1925 [00:20<00:40, 33.94it/s]
 30%|██▉       | 568/1925 [00:20<00:39, 34.76it/s]
 30%|██▉       | 576/1925 [00:21<00:37, 35.80it/s]
 30%|███       | 584/1925 [00:21<00:37, 35.69it/s]
 31%|███       | 592/1925 [00:21<00:39, 34.12it/s]
 31%|███       | 600/1925 [00:21<00:37, 35.45it/s]
 32%|███▏      | 608/1925 [00:22<00:38, 34.18it/s]
 32%|███▏      | 616/1925 [00:22<00:38, 34.23it/s]
 32%|███▏      | 624/1925 [00:22<00:39, 33.14it/s]
 33%|███▎      | 632/1925 [00:22<00:39, 33.10it/s]
 33%|███▎      | 640/1925 [00:22<00:37, 34.39it/s]
 34%|███▎      | 648/1925 [00:23<00:38, 32.89it/s]
 34%|███▍      | 656/1925 [00:23<00:35, 35.78it/s]
 34%|███▍      | 664/1925 [00:23<00:35, 35.67it/s]
 35%|███▍      | 672/1925 [00:23<00:36, 34.80it/s]
 35%|███▌      | 680/1925 [00:24<00:36, 34.12it/s]
 36%|███▌      | 688/1925 [00:24<00:35, 34.72it/s]
 36%|███▌      | 696/1925 [00:24<00:34, 35.89it/s]
 37%|███▋      | 704/1925 [00:24<00:34, 35.52it/s]
 37%|███▋      | 712/1925 [00:24<00:32, 37.46it/s]
 37%|███▋      | 720/1925 [00:25<00:30, 39.45it/s]
 38%|███▊      | 728/1925 [00:25<00:28, 42.48it/s]
 38%|███▊      | 736/1925 [00:25<00:26, 44.41it/s]
 39%|███▊      | 744/1925 [00:25<00:25, 45.69it/s]
 39%|███▉      | 752/1925 [00:25<00:24, 47.38it/s]
 39%|███▉      | 760/1925 [00:25<00:23, 49.32it/s]
 40%|███▉      | 768/1925 [00:26<00:23, 49.76it/s]
 40%|████      | 776/1925 [00:26<00:23, 48.99it/s]
 41%|████      | 784/1925 [00:26<00:22, 50.51it/s]
 41%|████      | 792/1925 [00:26<00:24, 46.70it/s]
 42%|████▏     | 800/1925 [00:26<00:24, 46.06it/s]
 42%|████▏     | 808/1925 [00:26<00:23, 47.76it/s]
 42%|████▏     | 816/1925 [00:27<00:23, 47.76it/s]
 43%|████▎     | 824/1925 [00:27<00:24, 45.58it/s]
 43%|████▎     | 832/1925 [00:27<00:23, 46.87it/s]
 44%|████▎     | 840/1925 [00:27<00:27, 39.63it/s]
 44%|████▍     | 848/1925 [00:27<00:24, 43.92it/s]
 44%|████▍     | 856/1925 [00:28<00:26, 40.77it/s]
 45%|████▍     | 864/1925 [00:28<00:25, 40.92it/s]
 45%|████▌     | 872/1925 [00:28<00:25, 41.85it/s]
 46%|████▌     | 880/1925 [00:28<00:25, 41.34it/s]
 46%|████▌     | 888/1925 [00:28<00:27, 37.56it/s]
 47%|████▋     | 896/1925 [00:29<00:25, 40.22it/s]
 47%|████▋     | 904/1925 [00:29<00:26, 38.21it/s]
 47%|████▋     | 912/1925 [00:29<00:26, 38.87it/s]
 48%|████▊     | 920/1925 [00:29<00:24, 40.60it/s]
 48%|████▊     | 928/1925 [00:29<00:24, 41.43it/s]
 49%|████▊     | 936/1925 [00:30<00:25, 39.20it/s]
 49%|████▉     | 944/1925 [00:30<00:25, 37.87it/s]
 49%|████▉     | 952/1925 [00:30<00:25, 38.00it/s]
 50%|████▉     | 960/1925 [00:30<00:25, 38.43it/s]
 50%|█████     | 968/1925 [00:30<00:24, 39.04it/s]
 51%|█████     | 976/1925 [00:31<00:26, 35.74it/s]
 51%|█████     | 984/1925 [00:31<00:25, 36.81it/s]
 52%|█████▏    | 992/1925 [00:31<00:25, 36.11it/s]
 52%|█████▏    | 1000/1925 [00:31<00:23, 39.42it/s]
 52%|█████▏    | 1008/1925 [00:32<00:24, 37.25it/s]
 53%|█████▎    | 1016/1925 [00:32<00:26, 34.82it/s]
 53%|█████▎    | 1024/1925 [00:32<00:25, 35.80it/s]
 54%|█████▎    | 1032/1925 [00:32<00:24, 36.05it/s]
 54%|█████▍    | 1040/1925 [00:32<00:24, 36.36it/s]
 54%|█████▍    | 1048/1925 [00:33<00:26, 33.63it/s]
 55%|█████▍    | 1056/1925 [00:33<00:25, 33.97it/s]
 55%|█████▌    | 1064/1925 [00:33<00:26, 32.87it/s]
 56%|█████▌    | 1072/1925 [00:33<00:26, 32.00it/s]
 56%|█████▌    | 1080/1925 [00:34<00:24, 33.83it/s]
 57%|█████▋    | 1088/1925 [00:34<00:25, 32.78it/s]
 57%|█████▋    | 1096/1925 [00:34<00:24, 33.19it/s]
 57%|█████▋    | 1104/1925 [00:34<00:23, 35.11it/s]
 58%|█████▊    | 1112/1925 [00:35<00:24, 33.82it/s]
 58%|█████▊    | 1120/1925 [00:35<00:23, 34.54it/s]
 59%|█████▊    | 1128/1925 [00:35<00:22, 34.91it/s]
 59%|█████▉    | 1136/1925 [00:35<00:23, 33.75it/s]
 59%|█████▉    | 1144/1925 [00:36<00:21, 36.12it/s]
 60%|█████▉    | 1152/1925 [00:36<00:22, 34.84it/s]
 60%|██████    | 1160/1925 [00:36<00:21, 35.45it/s]
 61%|██████    | 1168/1925 [00:36<00:22, 34.27it/s]
 61%|██████    | 1176/1925 [00:36<00:20, 36.16it/s]
 62%|██████▏   | 1184/1925 [00:37<00:21, 35.29it/s]
 62%|██████▏   | 1192/1925 [00:37<00:21, 34.82it/s]
 62%|██████▏   | 1200/1925 [00:37<00:21, 34.42it/s]
 63%|██████▎   | 1208/1925 [00:37<00:21, 33.60it/s]
 63%|██████▎   | 1216/1925 [00:38<00:19, 35.95it/s]
 64%|██████▎   | 1224/1925 [00:38<00:20, 34.05it/s]
 64%|██████▍   | 1232/1925 [00:38<00:20, 34.62it/s]
 64%|██████▍   | 1240/1925 [00:38<00:19, 35.90it/s]
 65%|██████▍   | 1248/1925 [00:39<00:18, 35.69it/s]
 65%|██████▌   | 1256/1925 [00:39<00:18, 35.71it/s]
 66%|██████▌   | 1264/1925 [00:39<00:19, 33.89it/s]
 66%|██████▌   | 1272/1925 [00:39<00:19, 33.75it/s]
 66%|██████▋   | 1280/1925 [00:39<00:18, 35.03it/s]
 67%|██████▋   | 1288/1925 [00:40<00:18, 34.74it/s]
 67%|██████▋   | 1296/1925 [00:40<00:18, 33.25it/s]
 68%|██████▊   | 1304/1925 [00:40<00:17, 34.57it/s]
 68%|██████▊   | 1312/1925 [00:40<00:18, 33.15it/s]
 69%|██████▊   | 1320/1925 [00:41<00:17, 35.08it/s]
 69%|██████▉   | 1328/1925 [00:41<00:17, 33.63it/s]
 69%|██████▉   | 1336/1925 [00:41<00:17, 34.08it/s]
 70%|██████▉   | 1344/1925 [00:41<00:16, 34.35it/s]
 70%|███████   | 1352/1925 [00:42<00:17, 33.20it/s]
 71%|███████   | 1360/1925 [00:42<00:17, 31.64it/s]
 71%|███████   | 1368/1925 [00:42<00:17, 32.70it/s]
 71%|███████▏  | 1376/1925 [00:42<00:16, 33.24it/s]
 72%|███████▏  | 1384/1925 [00:43<00:16, 32.62it/s]
 72%|███████▏  | 1392/1925 [00:43<00:16, 32.16it/s]
 73%|███████▎  | 1400/1925 [00:43<00:15, 33.55it/s]
 73%|███████▎  | 1408/1925 [00:43<00:15, 32.55it/s]
 74%|███████▎  | 1416/1925 [00:44<00:15, 32.44it/s]
 74%|███████▍  | 1424/1925 [00:44<00:14, 33.90it/s]
 74%|███████▍  | 1432/1925 [00:44<00:15, 32.53it/s]
 75%|███████▍  | 1440/1925 [00:44<00:14, 32.90it/s]
 75%|███████▌  | 1448/1925 [00:44<00:13, 35.69it/s]
 76%|███████▌  | 1456/1925 [00:45<00:13, 35.53it/s]
 76%|███████▌  | 1464/1925 [00:45<00:12, 35.70it/s]
 76%|███████▋  | 1472/1925 [00:45<00:13, 33.79it/s]
 77%|███████▋  | 1480/1925 [00:45<00:13, 33.79it/s]
 77%|███████▋  | 1488/1925 [00:46<00:12, 35.15it/s]
 78%|███████▊  | 1496/1925 [00:46<00:11, 35.89it/s]
 78%|███████▊  | 1504/1925 [00:46<00:11, 36.89it/s]
 79%|███████▊  | 1512/1925 [00:46<00:12, 33.92it/s]
 79%|███████▉  | 1520/1925 [00:47<00:11, 35.23it/s]
 79%|███████▉  | 1528/1925 [00:47<00:11, 34.74it/s]
 80%|███████▉  | 1536/1925 [00:47<00:10, 36.19it/s]
 80%|████████  | 1544/1925 [00:47<00:11, 34.49it/s]
 81%|████████  | 1552/1925 [00:47<00:10, 35.04it/s]
 81%|████████  | 1560/1925 [00:48<00:10, 35.28it/s]
 81%|████████▏ | 1568/1925 [00:48<00:10, 34.25it/s]
 82%|████████▏ | 1576/1925 [00:48<00:09, 35.71it/s]
 82%|████████▏ | 1584/1925 [00:48<00:10, 34.08it/s]
 83%|████████▎ | 1592/1925 [00:49<00:09, 34.74it/s]
 83%|████████▎ | 1600/1925 [00:49<00:09, 35.73it/s]
 84%|████████▎ | 1608/1925 [00:49<00:08, 35.54it/s]
 84%|████████▍ | 1616/1925 [00:49<00:09, 34.17it/s]
 84%|████████▍ | 1624/1925 [00:50<00:09, 32.91it/s]
 85%|████████▍ | 1632/1925 [00:50<00:08, 34.89it/s]
 85%|████████▌ | 1640/1925 [00:50<00:08, 31.79it/s]
 86%|████████▌ | 1648/1925 [00:50<00:08, 32.53it/s]
 86%|████████▌ | 1656/1925 [00:50<00:07, 36.42it/s]
 86%|████████▋ | 1664/1925 [00:51<00:07, 34.91it/s]
 87%|████████▋ | 1672/1925 [00:51<00:07, 34.44it/s]
 87%|████████▋ | 1680/1925 [00:51<00:07, 34.85it/s]
 88%|████████▊ | 1688/1925 [00:51<00:07, 33.64it/s]
 88%|████████▊ | 1696/1925 [00:52<00:06, 33.67it/s]
 89%|████████▊ | 1704/1925 [00:52<00:06, 34.84it/s]
 89%|████████▉ | 1712/1925 [00:52<00:06, 32.54it/s]
 89%|████████▉ | 1720/1925 [00:52<00:06, 34.06it/s]
 90%|████████▉ | 1728/1925 [00:53<00:05, 34.28it/s]
 90%|█████████ | 1736/1925 [00:53<00:05, 35.48it/s]
 91%|█████████ | 1744/1925 [00:53<00:04, 37.39it/s]
 91%|█████████ | 1752/1925 [00:53<00:04, 36.76it/s]
 91%|█████████▏| 1760/1925 [00:53<00:04, 37.05it/s]
 92%|█████████▏| 1768/1925 [00:54<00:04, 37.17it/s]
 92%|█████████▏| 1776/1925 [00:54<00:04, 35.45it/s]
 93%|█████████▎| 1784/1925 [00:54<00:03, 37.41it/s]
 93%|█████████▎| 1792/1925 [00:54<00:03, 37.38it/s]
 94%|█████████▎| 1800/1925 [00:54<00:03, 37.88it/s]
 94%|█████████▍| 1808/1925 [00:55<00:03, 37.56it/s]
 94%|█████████▍| 1816/1925 [00:55<00:03, 34.71it/s]
 95%|█████████▍| 1824/1925 [00:55<00:02, 34.99it/s]
 95%|█████████▌| 1832/1925 [00:55<00:02, 34.30it/s]
 96%|█████████▌| 1840/1925 [00:56<00:02, 33.33it/s]
 96%|█████████▌| 1848/1925 [00:56<00:02, 34.27it/s]
 96%|█████████▋| 1856/1925 [00:56<00:01, 34.69it/s]
 97%|█████████▋| 1864/1925 [00:56<00:01, 35.04it/s]
 97%|█████████▋| 1872/1925 [00:57<00:01, 34.99it/s]
 98%|█████████▊| 1880/1925 [00:57<00:01, 35.36it/s]
 98%|█████████▊| 1888/1925 [00:57<00:01, 35.85it/s]
 98%|█████████▊| 1896/1925 [00:57<00:00, 36.69it/s]
 99%|█████████▉| 1904/1925 [00:57<00:00, 35.64it/s]
 99%|█████████▉| 1912/1925 [00:58<00:00, 36.29it/s]
100%|█████████▉| 1920/1925 [00:58<00:00, 35.97it/s]
100%|██████████| 1925/1925 [00:58<00:00, 32.96it/s]

This analysis reveals that the hour of the day is the most important feature for predicting bike sharing demand. This example also illustrates a specific property of SAGE: it tends to distribute importance over correlated features. This can be seen for the temperature and “feel temperature” features, which have a near-perfect correlation, as seen in the correlation matrix below, and are both assigned similar importance. This property is a consequence of the axioms of Shapley values, and contrasts with other feature importance methods, such as LOCO or CFI.

corr_mat = np.corrcoef(X_train, rowvar=False)
fig, ax = plt.subplots()
ax.imshow(corr_mat, cmap="coolwarm", vmin=-1, vmax=1)
ax.set_xticks(np.arange(corr_mat.shape[0]))
ax.set_yticks(np.arange(corr_mat.shape[0]))
ax.set_xticklabels(
    df.drop(columns=["count"]).columns.tolist(), rotation=45, ha="right"
)
ax.set_yticklabels(df.drop(columns=["count"]).columns.tolist())
cbar = ax.figure.colorbar(
    ax.imshow(corr_mat, cmap="coolwarm", vmin=-1, vmax=1), label="correlation"
)
plt.tight_layout()
plt.show()
plot msage

References#

Total running time of the script: (1 minutes 4.070 seconds)

Estimated memory usage: 221 MB

Gallery generated by Sphinx-Gallery