論文中に 「SHAP値」として登場する用語。
SHAP値 とは:ゲーム理論のShapley値に基づき、各特徴量が「予測値にどれだけ寄与したか」を公平に分配する説明手法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import pandas as pd import shap import xgboost as xgb df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['年度']==2023].dropna() features = ['A1101', 'A4101', 'I3101', 'F2401', 'F2101'] X = df[features] y = df['D1101'] ## XGBoost で学習 model = xgb.XGBRegressor(n_estimators=100, max_depth=4, random_state=42).fit(X, y) ## TreeSHAP — 高速(多項式時間) explainer = shap.TreeExplainer(model) shap_values = explainer.shap_values(X) ## 1. Summary plot(全体的な重要度と方向) shap.summary_plot(shap_values, X, plot_type='dot') ## 2. Bar plot(mean |SHAP| ランキング) shap.summary_plot(shap_values, X, plot_type='bar') ## 3. Force plot(個別予測の説明 — 1 サンプル) shap.force_plot(explainer.expected_value, shap_values[0], X.iloc[0], matplotlib=True) ## 4. Dependence plot(特徴量と SHAP の関係 + 交互作用色付け) shap.dependence_plot('A4101', shap_values, X, interaction_index='I3101') ## 5. Waterfall plot(最も詳細な個別予測説明) shap.waterfall_plot(shap.Explanation(values=shap_values[0], base_values=explainer.expected_value, data=X.iloc[0].values, feature_names=features)) |
1 2 3 4 5 6 7 8 9 10 11 12 | from sklearn.neural_network import MLPRegressor from sklearn.preprocessing import StandardScaler X_scaled = StandardScaler().fit_transform(X) nn = MLPRegressor(hidden_layer_sizes=(16, 8), max_iter=2000, random_state=42).fit(X_scaled, y) ## KernelSHAP — モデル非依存 ## background data を 50 件にサブサンプル(高速化) background = shap.sample(X_scaled, 30) explainer = shap.KernelExplainer(nn.predict, background) shap_values = explainer.shap_values(X_scaled[:5], nsamples=100) print(f'1サンプル目の SHAP値: {shap_values[0]}') |
1 2 3 4 5 6 7 8 9 | from sklearn.inspection import permutation_importance, partial_dependence, PartialDependenceDisplay ## Permutation Importance(モデル非依存・汎化重要度) result = permutation_importance(model, X, y, n_repeats=10, random_state=42, scoring='r2') for i in result.importances_mean.argsort()[::-1]: print(f'{features[i]:10s} : {result.importances_mean[i]:.3f} ± {result.importances_std[i]:.3f}') ## Partial Dependence Plot — 関係の形状 PartialDependenceDisplay.from_estimator(model, X, features=[1, 2], grid_resolution=20) |
1 2 3 4 5 6 7 8 9 10 | import lime import lime.lime_tabular ## LIME — 単一予測の局所線形近似 explainer = lime.lime_tabular.LimeTabularExplainer( X.values, feature_names=features, mode='regression', random_state=42) ## 1 サンプル目の LIME 説明 exp = explainer.explain_instance(X.values[0], model.predict, num_features=5) exp.show_in_notebook() |
SHAP は「各特徴量が予測に対して何 pt 寄与したか」を、 ゲーム理論の Shapley 値に基づいて公平に分配する手法。 たとえば SSDSE-B-2026 で「都道府県の出生率を予測する Random Forest」を作り、 ある県の予測値が 1.40 で平均 1.30 のとき、 SHAP は「人口密度が +0.05、 平均所得が +0.08、 高齢化率が -0.03 寄与した」のように分解する。
直感で全体像を掴んだら、 次は厳密な定義を見ます。 数式は短いものでも、 「何を入力にして、 何を出力するのか」を意識して読むと早く慣れます。
上の数式に出てくる各記号が何を表すかを、 言葉で翻訳します。 1 つずつ自分の言葉で言い換えられるようになると、 論文や教科書のスピードが一気に上がります。
| 記号 | 意味(言葉での説明) |
|---|---|
| $\phi_i$ | 特徴量 $i$ の SHAP 値(予測への寄与) |
| $N$ | 全特徴量の集合 |
| $S$ | $i$ を含まない部分集合 |
| $v(S)$ | $S$ だけで学習したときの予測値 |
| $|S|!(n-|S|-1)!/n!$ | 対称性を保つための重み |
数式だけでは「分かった気になる」だけで終わりがち。 ここで SSDSE-B-2026(教育用標準データセット — 47 都道府県 × 100+ 指標、 2018-2023 年度)の実値を当てはめて、 SHAP の挙動を電卓的に追体験します。
SSDSE-B-2026 は 統計センターの SSDSE 配布ページ から CSV を直接ダウンロードできます。 本サイトでは data/raw/SSDSE-B-2026.csv に配置している前提でコードを書いています。
以下のコードは最小限の構成です。 pd.read_csv('data/raw/SSDSE-B-2026.csv') を直書きしているので、 同じ階層に CSV を置けばそのまま動きます。 変数化しないのは、 初学者が「パスをどこに書くべきか」で迷わないようにするためです。
# SHAP を SSDSE-B-2026 で確かめる最小コード
import pandas as pd
import numpy as np
# 1) SSDSE-B-2026(教育用標準データセット)を読み込み
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=1)
print('shape:', df.shape) # (564, 112) — 47 都道府県 × 6 年度
print('cols head:', list(df.columns[:8]))
# 2) 直近年度(2023 年度)に絞る
df23 = df[df['年度'] == 2023].copy()
print('rows in 2023:', len(df23))
# 3) SHAP を動かすために必要な列だけ取り出す
y = df23['合計特殊出生率'].astype(float)
x = df23['総人口'].astype(float)
print('y stats:', y.describe().round(3).to_dict())
print('x stats:', x.describe().round(0).to_dict())
# 4) SHAP の本処理(このページの主題)
# — 具体実装は同カテゴリの個別ページにも掲載
print('---- SHAP 結果 ----')
print('mean y:', y.mean().round(3), '/ std y:', y.std().round(3))
print('mean x:', x.mean().round(0), '/ std x:', x.std().round(0))
print('corr(x, y):', y.corr(x).round(3))
うまく動かないときは ①data/raw/SSDSE-B-2026.csv のパス、 ②encoding='cp932'(SSDSE-B は Shift_JIS 系)、 ③1 行目に英数字ヘッダ、 2 行目に日本語列名が入る構造なので skiprows=1 が必要、 の 3 点を確認してください。
この用語を実務で使うときにつまずきやすい点を、 失敗パターン別に整理しました。 1 度経験すれば回避できるものばかりですが、 先に知っておくと事故が大幅に減ります。
SHAP と一緒に覚えておくと選択肢が広がる関連手法。 状況によって使い分けが必要なので、 それぞれの強みと弱みを 1 行で言えるようにしておきましょう。
表中の各手法は本サイト内に個別ページが用意されているものが多いです。 興味を持った概念は、 横展開的に読むと体系的な理解が早く進みます。