論文一覧に戻る 📚 用語解説(ジャストインタイム型データサイエンス教育)
SHAP値
SHAP (SHapley Additive exPlanations)
ゲーム理論のShapley値に基づき、各特徴量が「予測値にどれだけ寄与したか」を公平に分配する説明手法。
機械学習SHAPShapley値shap

🔖 キーワード索引

SHAPShapley値説明可能性XAI特徴量寄与TreeSHAPKernelSHAPLIME解釈可能性SSDSE-B-2026

shap」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「shap」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

SHAP 値Shapley 値特徴量寄与TreeSHAPKernelSHAPDeepSHAP局所説明 local大域説明 globalforce plotsummary plotLIME 対比解釈可能性 XAI

これらのキーワードは「shap の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

予測の理由を分ける道具です。

どの項目が結果に影響したか知るために使います。

テストの点数にどの勉強法が効いたか調べる感じです。

この章ではSHAP値の基本を学びます。

📖 包括的解説 — この概念を完全マスター

📍 学習の3ステップ

  1. 定義を理解する:この概念は何か? 数式や条件を確認
  2. 具体例を見る:実データ(SSDSE 等)で計算してみる
  3. 応用する:自分のデータに適用、 結果を解釈

🔧 Python実装パターン

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1301(15歳未満人口) A1303(65歳以上人口) A4101(出生数) B4101(年平均気温) 北海道 5,092,000 514,000 1,681,000 24,430 11.0 東京都 14,086,000 1,513,000 3,205,000 86,348 17.6 沖縄県 1,468,000 236,000 350,000 12,549 23.8 …(全 47 行)
 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
36
37
38
39
40
41
42
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['SSDSE-B-2026']==2023].dropna()

features = ['A1101', 'A1301', 'A1303', 'L3221', 'B4101']
X = df[features]
y = df['A4101']

## 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 サンプル目 = 北海道)
print(f'1 サンプル目の予測値: {model.predict(X.iloc[[0]])[0]:,.1f}')
print(f'ベース値(背景平均): {explainer.expected_value:,.1f}')
print(f'寄与の合計: {shap_values[0].sum():+,.1f}')
top3 = sorted(zip(features, shap_values[0]), key=lambda t: -abs(t[1]))[:3]
print('上位特徴量寄与: ' + '  '.join(f'{n}={v:+,.1f}' for n, v in top3))

## 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('A1101', shap_values, X, interaction_index='A1303')

## 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))
🎯 このコードでやること:TreeSHAP を使い、 SSDSE-B-2026 から学習した勾配ブースティングモデルの予測を都道府県単位で説明します。
📥 入力例(df.head()) df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1]) df = df[df['SSDSE-B-2026']==2023].head() # 期待される df.head()(先頭列 "SSDSE-B-2026" は年度、 簡略表示): # SSDSE-B-2026 Code Prefecture A1101 A1301 A1303 ... # 0 2023 R01000 北海道 5092000 514000 1681000 ... # 1 2023 R02000 青森県 1184000 118000 417000 ... # 2 2023 R03000 岩手県 1163000 120000 407000 ... # 3 2023 R04000 宮城県 2264000 250000 662000 ... # 4 2023 R05000 秋田県 914000 83000 357000 ... # X = features(A1101 総人口, A1301 15歳未満人口, A1303 65歳以上人口, L3221 消費支出, B4101 年平均気温) # y = A4101(出生数)
📤 実行例(実行時の標準出力) 1 サンプル目の予測値: 24,429.7 ベース値(背景平均): 15,473.8 寄与の合計: +8,955.9 (= 予測 - ベース、 加法性が成立) 上位特徴量寄与: A1301=+7,315.7 A1101=+1,978.8 A1303=-385.6
💬 読み方:TreeSHAP は加法的:各特徴量の寄与を足すと(ベース値からのズレ=予測値 − 平均)になる。 都道府県ごとの差を「人口効果 +X、 所得効果 -Y」のように分解できる。

② KernelSHAP — モデル非依存(NN・SVM 等にも)

📤 実行例(実行時の標準出力)
1サンプル目の SHAP値: [ -227.57166812  -313.99551577  -139.96680974   -66.9869587
 -1351.34604176]
合計 ≈ -2099.9(背景平均からのズレ)
背景データ 30 件で KernelSHAP を近似計算(nsamples=100)

💬 読み方:KernelSHAP は重み付き線形回帰で Shapley 値を近似。 nsamples を増やすほど精度が上がるが計算は重い。 NN・SVM 等 TreeSHAP が使えないモデルで採用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import shap
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]}')
🎯 このコードでやること:KernelSHAP を用いて、 SSDSE-B-2026 から学習したニューラル回帰モデルの予測を分解します。 モデル非依存版です。
📥 入力例(df.head()) X_scaled = StandardScaler().fit_transform(X) # X.shape ≒ (47, p) — 47 都道府県 × p 個の社会経済特徴量 # y = 都道府県別の目的指標(例: 出生数 c1、 1 人あたり所得 など) # NN を fit するため特徴量を標準化済み(平均 0、 分散 1)

③ scikit-learn の Permutation Importance(代替手法)

📤 実行例(実行時の標準出力)
A1301      : 0.707 ± 0.115
A1101      : 0.192 ± 0.035
A1303      : 0.034 ± 0.003
L3221      : 0.000 ± 0.000
B4101      : 0.000 ± 0.000
# 上位ほど予測精度への寄与が大きい(15歳未満人口 A1301 が支配的)

💬 読み方:Permutation Importance は「シャッフルしたら精度がどれだけ落ちるか」で重要度を測る。 SHAP(個別寄与)と異なり、 全体的・大域的な重要度。 ここでは A1301(15歳未満人口)が突出し、 mean|SHAP| で 1 位だった A1101(総人口)を上回る。 両者は相関 0.997 とほぼ同じ情報を持つため、 どちらが上位に来るかは指標の定義で入れ替わる。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# ── この抜粋で使うモデルとデータを用意します ──
import pandas as pd
import matplotlib.pyplot as plt   # PDP の描画に必要
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.inspection import permutation_importance, partial_dependence, PartialDependenceDisplay

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].dropna()   # 2023 年の 47 都道府県
features = ['A1101', 'A1301', 'A1303', 'L3221', 'B4101']
X = df[features].astype(float).values
y = df['A4101'].astype(float).values           # 出生数
model = GradientBoostingRegressor(random_state=42).fit(X, y)

## 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)
🎯 このコードでやること:scikit-learn の Permutation Importance を使って、 SHAP の代替として特徴量の重要度を測定します。
📥 入力例(df.head()) X.head() の例: # A1101 A1301 A1303 L3221 B4101 # 0 5092000 514000 1681000 ... ... # 1 1184000 118000 417000 ... ... # 2 1163000 120000 407000 ... ... # y = SSDSE-B-2026 の出生数 A4101(目的変数)

④ LIME — 局所的な近似

📤 実行例(実行時の標準出力)
LIME 局所説明(1 サンプル目):
  A1101 > 3000000 : +0.412
  L3221 < 250000  : -0.183
  B4101 ∈ [14,16] : +0.071
R² (局所近似モデル): 0.91  — 周辺で線形近似が良好

💬 読み方:LIME は 1 サンプル周辺だけで線形近似。 局所的に分かりやすいが、 SHAP のような数学的一貫性(加法性)は保証されない点に注意。

 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()
🎯 このコードでやること:LIME を使って、 SSDSE-B-2026 上で 1 件の予測を局所線形モデルで近似し、 寄与を可視化します。
📥 入力例(df.head()) X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42) # 47 都道府県を訓練・テストに分割。 X は標準化済み数値特徴量、 y は目的変数。 # 1 サンプルに対して局所線形モデルで近似し、 各特徴量の寄与を抽出する想定。

📍 あなたが今見ているもの

🍰 まずはやさしく

予測の中身を説明する手法です。

AIがなぜその答えを出したか分かるようにします。

スマホのアプリがなぜこの広告を出したか探る感じです。

ここでは定義から実装までを順番に読みます。

論文中に 「SHAP値」として登場する用語。

SHAP値 とは:ゲーム理論のShapley値に基づき、各特徴量が「予測値にどれだけ寄与したか」を公平に分配する説明手法。

本ページでは「shap」を扱う。 統計データ分析コンペティション (2026) の教材で、 SSDSE-B-2026 (47 都道府県 × 複数年 × 100 超列) の実データを使った再現可能な学習を目指す。

「shap」は統計・データサイエンスの体系における重要概念のひとつ。 本ページは「定義・直感・数式・実装・落とし穴・関連手法」の 6 視点で構成され、 各視点は独立して読めるが順序通り読むと体系的な理解が得られる。

🎨 直感で掴む — SHAP の本質

🍰 まずはやさしく

予測の結果を分けたレシートのようなものです。

それぞれの項目がどれだけ貢献したか計算します。

部活の試合で誰がどれだけ得点に貢献したか分ける感じです。

ここではSHAP値のイメージを掴んでいきます。

SHAP は「各特徴量が予測に対して何 pt 寄与したか」を、 ゲーム理論の Shapley 値に基づいて公平に分配する手法。 たとえば SSDSE-B-2026 で「都道府県の出生率を予測する Random Forest」を作り、 ある県の予測値が 1.40 で平均 1.30 のとき、 SHAP は「人口密度が +0.05、 平均所得が +0.08、 高齢化率が -0.03 寄与した」のように分解する。

💡 ポイント:SHAP を初めて学ぶときは「正確な定義」より「どんな問題を解くための道具か」を先に押さえてください。 数式は次の「📐 数式」セクションで丁寧に展開します。
📌 比喩がうまく刺さらないときは、 自分の身近な例(家計簿・スポーツの記録・成績表)に置き換えてみると理解が定着します。 SSDSE-B-2026 を電卓代わりに触りながら、 上の説明を再読すると効果的です。

🎨 直感で掴む — SHAP は「予測のレシート」

SHAP は機械学習モデルの予測を、 各特徴量の 寄与額 に分解する手法。 ちょうどスーパーのレシートが「合計 1,580 円 = キャベツ 200 + 牛乳 350 + パン 280 + ...」と内訳を示すように、 SHAP は「予測値 0.92 = 平均 0.5 + 人口 +0.18 + 出生率 -0.05 + 平均気温 +0.15 + 教育水準 +0.14」と 足し算で因果寄与を可視化します。

なぜ Shapley 値なのか?

単純な「特徴量重要度」(feature_importances_) は「モデル全体での平均的な貢献」しか教えてくれない。 一方で、 SHAP は 個々のサンプルについて「この予測がなぜこの値か」を説明できる。 さらに、 ゲーム理論の Shapley 値が満たす 4 つの公理 (Efficiency, Symmetry, Dummy, Additivity) を満たす、 数学的に唯一の分解です。

手法 説明粒度 公理保証 計算量 主な弱点
feature_importances_グローバルのみなし非常に軽い個別予測の理由不明
Permutation Importanceグローバルなし相関で過大評価
LIMEローカルなし不安定 (毎回違う値)
SHAP (TreeSHAP)ローカル + グローバル4 公理保証木モデルなら O(TLD^2)相関特徴量の解釈に注意
SHAP (KernelSHAP)汎用モデル近似的に保証O(2^M) サンプリング大規模特徴で遅い

SHAP の最大の魅力は 「グローバル説明とローカル説明の整合性」。 個別予測の寄与額を全サンプルで集計すると、 そのままモデル全体の重要度になる。 LIME や Permutation には無い性質です。

📐 数式または定義 — SHAP の形式的表現

🍰 まずはやさしく

寄与度(影響した度合い)を公平に分ける計算式です。

正しく計算するためのルールを確認するために使います。

買い物で誰がいくら出したか公平に分ける感じです。

ここでは数式を使って詳しい定義を読みます。

直感で全体像を掴んだら、 次は厳密な定義を見ます。 数式は短いものでも、 「何を入力にして、 何を出力するのか」を意識して読むと早く慣れます。

【Shapley 値(特徴量 $i$ の寄与の期待値)】
$$ \phi_i(v) = \sum_{S \subseteq N \setminus \{i\}} \frac{|S|!(n-|S|-1)!}{n!} \bigl[v(S \cup \{i\}) - v(S)\bigr] $$
この数式は「SHAP がどう計算されるか」を最短で示したもの。 記号の意味は次の「🔬 数式を言葉で読み解く」で 1 つずつ解説します。
📚 数式が苦手な方へ:1 つの長い式を一度に理解しようとせず、 記号ごとに「言葉に翻訳」するのが王道。 紙に書き写してから、 自分の言葉で音読してみてください。

📐 数式 — Shapley 値と SHAP の定式化

特徴量 $i$ の Shapley 値:

$$ \phi_i = \sum_{S \subseteq F \setminus \{i\}} \frac{|S|!\,(|F|-|S|-1)!}{|F|!} \bigl[ v(S \cup \{i\}) - v(S) \bigr] $$

ここで $F$ は全特徴量集合、 $S$ は特徴量サブセット、 $v(S)$ は $S$ だけを使ったモデル予測。 SHAP は $v(S) = E[f(x) | x_S]$ と定義し、 全特徴を使った場合と部分集合の場合の差を Shapley 公式で重み付け平均します。

最終的に、 任意のサンプル $x$ に対して以下の加法分解が成立 (Local Accuracy):

$$ f(x) = \phi_0 + \sum_{i=1}^{M} \phi_i $$

$\phi_0$ は ベース値 (=訓練データ全体での平均予測)、 $\phi_i$ は特徴量 $i$ の寄与額。 この式の最大の意味は「予測値が必ず寄与額の和になる」こと。 これは Shapley 値の Efficiency 公理から自動的に保証されます。

数式を言葉で読み解く

この 4 公理を満たす分配は Shapley 値が唯一 (Shapley 1953)。 だから SHAP は「説明可能性手法の中で数学的に最も基礎付けられた」と評価されています。

📐 Shapley 値の公理 — 数式を 4 つの直感で読み解く

SHAP の根本にある Shapley 値は、 協力ゲーム理論で 1953 年に Lloyd Shapley が提案した「複数プレイヤーの貢献を公平に分配する唯一の方法」である。 SHAP はこれを機械学習に応用しただけで、 公理(axioms)はそのまま継承される。 ここでは 4 つの公理を SSDSE-B-2026 の文脈で具体的に読み解く。 これらの公理を満たす分配方法は Shapley 値のみであることが数学的に証明されている(一意性定理)。

公理 1: Efficiency(効率性 / Local Accuracy)

数式:$\sum_{j=1}^{d} \phi_j = f(x) - E[f(X)]$
SSDSE-B-2026 での意味:全特徴量の SHAP 値の合計は、 「その県の予測値」と「全県平均の予測値」の差に等しい。 例:東京の予測 100 兆円、 全国平均予測 10 兆円 → SHAP 値の合計は +90 兆円。 1 円のずれも許さない厳密等式である。
直感:「分配したお金の合計は元のお金と一致しなければならない」というレシートの原則。

公理 2: Symmetry(対称性)

数式:もし $\forall S \subseteq N \setminus \{i,j\}, v(S \cup \{i\}) = v(S \cup \{j\})$ なら $\phi_i = \phi_j$。
SSDSE-B-2026 での意味:仮に「総人口」と「日本人人口」がモデルから見て完全に区別できない(任意の組合せで同じ予測値を生む)場合、 SHAP 値は同じ値になる。
直感:「全く同じ貢献をした 2 人のメンバーには同じ報酬を払う」という公平性の原則。

公理 3: Dummy(ダミー / Null Player)

数式:もし $\forall S, v(S \cup \{i\}) = v(S)$ なら $\phi_i = 0$。
SSDSE-B-2026 での意味:「年平均気温」が出生数の予測に一切影響しない特徴量だった場合、 その SHAP 値はゼロ。 図 3 で年平均気温の箱がほぼ 0 に張り付いていたのはこの公理の表れ。
直感:「何もしなかった人には報酬は払わない」。 これは feature selection の合理性も保証する。

公理 4: Additivity(加法性)

数式:$\phi_i(v_1 + v_2) = \phi_i(v_1) + \phi_i(v_2)$
SSDSE-B-2026 での意味:もし 2 つのモデル(例:RandomForest と XGBoost)の予測を足し合わせたアンサンブルを作った場合、 SHAP 値もそのまま足し算で求まる。 これは TreeSHAP の高速化アルゴリズムの根拠でもある。
直感:「貢献度の分配は、 ゲームを分解しても変わらない」。 アンサンブル学習との相性が抜群に良い理由。

一意性定理 — なぜ SHAP は「唯一」なのか

Shapley (1953) の一意性定理は次のように述べる:「Efficiency + Symmetry + Dummy + Additivity の 4 公理を同時に満たす分配方法は、 Shapley 値のみである」。 これは数学的な定理であり、 別の「公平な分配方法」を考えても、 これらの公理のいずれかを必ず破る。 LIME(局所線形近似)は Local Accuracy を厳密には満たさないため、 同じ意味での「公平さ」は保証されない。 これが SHAP が「説明手法のゴールドスタンダード」と呼ばれる根拠である。

Shapley 値の計算式(参考)

SHAP 値は次の和で定義される:

$\phi_i = \sum_{S \subseteq N \setminus \{i\}} \frac{|S|! (|N|-|S|-1)!}{|N|!} \big[ v(S \cup \{i\}) - v(S) \big]$

記号の意味:

この計算は厳密には全部分集合 $2^{|N|-1}$ 通りの和を取る必要があり、 $|N|=50$ で 10^15 通りと爆発する。 SHAP ライブラリの TreeSHAP / KernelSHAP / LinearSHAP はそれぞれモデル構造を活かして高速近似または厳密計算を実現する。

🔬 数式を言葉で読み解く — SHAP の記号辞書

上の数式に出てくる各記号が何を表すかを、 言葉で翻訳します。 1 つずつ自分の言葉で言い換えられるようになると、 論文や教科書のスピードが一気に上がります。

記号意味(言葉での説明)
$\phi_i$特徴量 $i$ の SHAP 値(予測への寄与)
$N$全特徴量の集合
$S$$i$ を含まない部分集合
$v(S)$$S$ だけで学習したときの予測値
$|S|!(n-|S|-1)!/n!$対称性を保つための重み
📌 読み下しのコツ:左から右に「主語 → 述語 → 目的語」と見立てて、 「これは何を、 どうしている式か?」と一文で要約してみてください。 慣れれば 5 秒で読めます。

🧮 実値で計算してみる — SSDSE-B-2026 で SHAP を体感

数式だけでは「分かった気になる」だけで終わりがち。 ここで SSDSE-B-2026(教育用標準データセット — 47 都道府県 × 100+ 指標、 2012-2023 年度)の実値を当てはめて、 SHAP の挙動を電卓的に追体験します。

👉 計算例:SSDSE-B-2026 で「総人口、 65 歳以上人口、 大学学生数、 婚姻件数」から合計特殊出生率(A4103)を XGBoost で予測。 ある県(例:東京、 出生率 1.04)の予測値分解を SHAP で計算すると、 base value 1.30 から「65歳以上人口比率 -0.20、 婚姻件数 +0.05、 大学学生数 +0.03、 …」のように 0.26 pt の差が説明できる。

SSDSE-B-2026 は 統計センターの SSDSE 配布ページ から CSV を直接ダウンロードできます。 本サイトでは data/raw/SSDSE-B-2026.csv に配置している前提でコードを書いています。

🧮 実値で計算してみる — SSDSE-B-2026 の SHAP 分解

SSDSE-B-2026 から「都道府県の年間出生数 (A4101)」を予測するモデルを構築し、 SHAP で 東京都の予測根拠を分解した結果 (XGBoost + TreeSHAP の出力例):

特徴量 東京都の値 全国平均 SHAP 値 $\phi_i$ 解釈
A1101 総人口14,124,0002,668,000+58,200人口圧倒的多 → 大きく押上
A1301 15歳未満1,541,000350,000+8,500少子化緩和の寄与
A4103 合計特殊出生率1.041.25-4,800出生率は全国平均以下 → 押下
A5101 婚姻件数73,20010,800+2,300婚姻多 → 押上
L3221 消費支出330,640295,400+1,100経済豊か → 微小押上
ベース値 $\phi_0$21,80021,800訓練データの平均予測
予測値 $f(x)$87,10021,800 + 58,200 + 8,500 - 4,800 + 2,300 + 1,100

注目すべきは 「総人口の寄与 +58,200 が出生率の押下 -4,800 を圧倒する」こと。 つまり SHAP は「東京は出生率が低いが、 母数となる人口が桁違いに多いため絶対値の出生数は最大」という絡まった因果関係を、 数値で明示的に分解してくれます。 単純な相関では見えない構造です。

🧮 数式に値を入れて手で計算する: SHAP 値の合計性

合成 3 特徴のモデルで予測 = 基準 + Σ SHAP を検証する。

Step 1: 基準値と SHAP

基準値 E[f] = 0.5 SHAP_x1 = +0.20 SHAP_x2 = -0.10 SHAP_x3 = +0.05

Step 2: 予測

f(x) = 0.5 + 0.20 - 0.10 + 0.05 = 0.65 主要寄与: x1 (+0.20)

🐍 Python で再現

1
2
3
4
5
6
import numpy as np
base = 0.5
shap = np.array([0.20, -0.10, 0.05])
pred = base + shap.sum()
print(f"予測: {pred}")
print(f"主要 index: {np.abs(shap).argmax()}")

📤 実行結果

予測: 0.65 主要 index: 0

💬 手計算 (Step 2) 0.65 と Python 出力が完全一致。

🎮 触って理解する

スライダーで特徴量の値を動かすと、 基準値(全体平均予測)から最終予測へ向かうウォーターフォール図がリアルタイムに更新されます。 赤は予測を押し上げる寄与、 青は押し下げる寄与。 各特徴の寄与額こそが SHAP 値(Shapley 値)です。

🧪 使う架空モデル(実データではありません)
あるカフェの「1 日の来客スコア」を 3 つの特徴量から予測する、 説明用の架空の加法モデルです。
f = 50 + 20·気温 + 15·話題度 + 10·天気 + 12·(気温 × 話題度)
各特徴の値は「その日の平均との差」(−1.0 〜 +1.0)としてスライダーで与えます。 平均との差が 0 のときが基準状態で、 基準値 E[f] = 50 になります。 紫の項は気温と話題度の相互作用(暑い日ほど話題の効果が乗る)で、 Shapley 値はこの相互作用も 2 特徴へ公平に折半します。

🔁 各特徴の寄与はどう決まる? — 全順列の限界貢献を平均

Shapley 値の定義は「特徴量を 1 つずつ加えていく全ての順番(順列)について、 その特徴を加えた瞬間の予測の増分(限界貢献)を求め、 平均する」というもの。 3 特徴なら順列は 3! = 6 通り。 下の表は現在のスライダー値での 6 通りの限界貢献と、 その平均(= SHAP 値)です。 相互作用があるため、 同じ特徴でも加える順番によって限界貢献が変わる点に注目してください。

💡 効率性(Efficiency):どんなスライダー値でも Σφi = 予測 f(x) − 基準値 E[f] が 1 の狂いもなく成立します(緑のパネルで常時検証)。 これは Shapley 値の 4 公理の 1 つで、 「分配した寄与の合計は、 説明したい差分にぴったり一致する」という保証です。

関連ページ: XAI(説明可能AI)ランダムフォレスト線形回帰重回帰分析回帰分析特徴量エンジニアリング。 なお LIME・Permutation Importance・TreeSHAP の解説は本ページ内(📍 直感・🐍 Python 実装)を参照してください。

🐍 Python 実装 — SHAP を SSDSE-B-2026 で動かす

🎯 このコードでやること: SSDSE の 10 変数から出生数(A4101)を予測する XGBoost を学習させ、 その予測を SHAP 値で 1 県ずつ分解します。 木モデルは係数が読めないので「なぜこの県の予測がこの値になったか」が分かりません。 SHAP は各特徴量が予測をどれだけ押し上げ/押し下げたかを加法的に分けるので、 予測の内訳が県ごとに読めるようになります。 なお pd.read_csv('data/raw/SSDSE-B-2026.csv') をパス変数にせず直書きしているのは、 初学者が「パスをどこに書くべきか」で迷わないようにするためです。 CSV を同じ階層に置けばそのまま動きます。

📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 SSDSE-B-2026(年度) A4103(合計特殊出生率) A1101(総人口) 北海道 2,023 1.06 5,092,000 東京都 2,023 0.99 14,086,000 沖縄県 2,023 1.6 1,468,000 …(全 47 行)
 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
# 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 都道府県 × 12 年度
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:', round(y.std(), 3))
print('mean x:', x.mean().round(0), '/ std x:', round(x.std(), 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 点を確認してください。

🐍 Python 実装① — XGBoost + TreeSHAP で SSDSE-B-2026 を分解

🎯 このコードでやること: SSDSE-B-2026 で「年間出生数 A4101」を予測する XGBoost モデルを学習し、 TreeSHAP で各都道府県の SHAP 値を計算する。 TreeSHAP は木モデル限定だが、 厳密計算で高速 (O(TLD²))。

📥 入力データ: data/raw/SSDSE-B-2026.csv (47 都道府県 × 110 変数)。 目的変数 A4101、 説明変数は人口・産業・教育系列を厳選。

df.shape = (47, 112) ← 2023 年度だけに絞った 47 都道府県 target = A4101 (年間出生数) features = ['A1101', 'A1301', 'A1303', 'A4103', 'A5101', 'A5102', 'L3221', 'E3101', 'E1101', 'B4101'] ← 10 個に絞る
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd, xgboost as xgb, shap

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].reset_index(drop=True)   # 2023 年度の 47 都道府県
features = ['A1101', 'A1301', 'A1303', 'A4103', 'A5101',
            'A5102', 'L3221', 'E3101', 'E1101', 'B4101']
X = df[features]
y = df['A4101']

model = xgb.XGBRegressor(n_estimators=200, max_depth=4, learning_rate=0.05, random_state=42)
model.fit(X, y)
explainer = shap.TreeExplainer(model)
shap_values = explainer(X)

print(f'ベース値 phi_0 = {explainer.expected_value:,.1f}')
tokyo_idx = df[df['Prefecture'] == '東京都'].index[0]
print(f'東京都 予測 = {model.predict(X.iloc[[tokyo_idx]])[0]:,.1f}')
print(f'東京都 SHAP 合計 = {shap_values.values[tokyo_idx].sum():,.1f}')
print(f'shap_values.values.shape = {shap_values.values.shape}')

📤 実行例:

ベース値 phi_0 = 15,460.3 東京都 予測 = 85,878.3 東京都 SHAP 合計 = 70,418.0 ← 予測 - ベース と完全に一致 shap_values.values.shape = (47, 10)

💬 結果の読み方: SHAP 値の合計 (=70,418.0) と予測値からベース値を引いた値 (85,878.3 − 15,460.3) が完全に一致。 これが Local Accuracy 公理の実証。 個々の SHAP 値を見れば、 東京都の予測根拠が変数別に分解されます。

🐍 Python 実装② — summary_plot で全都道府県を一望

🎯 このコードでやること: shap.summary_plot で全 47 都道府県 × 10 特徴量の SHAP 値を一枚の図に描き、 「どの特徴量が出生数予測にどれだけ効いているか」を可視化する。

📥 入力データ: 上記モデルの shap_values オブジェクト。 各行が都道府県、 各列が特徴量。

shap_values.values.shape = (47, 10) | A1101 A1301 A1303 A4103 A5101 ... | 東京| +53,699 +3,991 +12,454 -5 +156 ...| 北海| +2,616 +6,185 -311 -9 +233 ...|
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import shap, matplotlib.pyplot as plt

shap.summary_plot(shap_values, X, plot_type='dot', show=False)
plt.tight_layout()
plt.savefig('shap_summary.png', dpi=120)

# 各特徴量の平均絶対 SHAP (=グローバル重要度)
import numpy as np
mean_abs = np.abs(shap_values.values).mean(axis=0)
order = np.argsort(-mean_abs)
for i in order:
    print(f'{features[i]:8s}: {mean_abs[i]:8,.1f}')

📤 実行例:

A1101 : 9,812.8 ← 総人口が圧倒的に効く A1301 : 2,448.9 A1303 : 729.5 A5101 : 200.1 A5102 : 69.6 E3101 : 54.0 E1101 : 48.1 A4103 : 12.4 ← 出生率は意外に小さい L3221 : 9.2 B4101 : 8.7

💬 結果の読み方: グローバル重要度では「総人口」が他を圧倒。 一見当然だが、 SHAP の偉さは 個別予測ではこの順位が変わること (例: 沖縄県では A1101 が押下げに回り、 A1301 が最大の押上げになる)。 summary_plot のドット分布で「特徴量の値 (赤=大、 青=小) × SHAP 値」を一望できます。

🐍 Python 実装③ — waterfall_plot で個別予測を可視化

🎯 このコードでやること: 沖縄県 (出生率全国一位 1.60、 人口は中規模) の予測を waterfall プロットで可視化。 ベース値からスタートし、 各特徴量の寄与を積み上げて予測値に到達する様子を描く。

📥 入力データ: 沖縄県 (Prefecture=="沖縄県") の特徴量ベクトルと、 対応する shap_values の行。

沖縄県 (R47000): A1101=1,468,000 A1301=236,000 A4103=1.60 A5101=26,410 実測の A4101 (出生数) = 12,549
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import shap, matplotlib.pyplot as plt

okinawa_idx = df[df['Prefecture'] == '沖縄県'].index[0]
shap.plots.waterfall(shap_values[okinawa_idx], max_display=10, show=False)
plt.tight_layout()
plt.savefig('shap_okinawa.png', dpi=120)

print('沖縄県 各特徴量 SHAP 値:')
for name, v in zip(features, shap_values.values[okinawa_idx]):
    sign = '+' if v >= 0 else ''
    print(f'  {name:8s}: {sign}{v:8,.1f}')

📤 実行例:

沖縄県 各特徴量 SHAP 値: A1101 : -5,899.7 ← 人口 147 万は全国平均 265 万を下回る → 押下げ A1301 : + 2,810.8 ← 15 歳未満 23.6 万 → 最大の押上げ A1303 : -345.4 A4103 : + 11.9 ← 出生率 1.60 (全国最高) でも寄与はごく小さい A5101 : + 320.7 A5102 : + 71.4 L3221 : + 14.7 E3101 : -37.9 E1101 : + 122.8 B4101 : + 17.9 予測 = 15,460.3 + (-2,912.8) = 12,547.5 (実値 12,549)

💬 結果の読み方: 東京都とは正反対の構造で、 沖縄県では 総人口 A1101 が -5,899.7 と押下げに回り、 15 歳未満人口 A1301 の +2,810.8 が最大の押上げになる。 出生率 A4103 は全国一位の 1.60 だが寄与は +11.9 とごく小さい — 「出生率が高い=出生数の予測が押し上がる」ではない点が重要で、 モデルは出生数の水準をほぼ人口規模で説明している。 これが SHAP の真価で、 「同じモデルなのに、 個別予測ごとに最重要特徴が変わる」のを定量化できる。

🐍 Python 実装④ — dependence_plot で非線形効果を可視化

🎯 このコードでやること: 「総人口 A1101 が増えると SHAP 値はどう変わるか」を全 47 都道府県でプロット。 単純線形なら直線になるが、 ツリーモデルは非線形なので「人口 200 万を境に効きが変わる」など階段状になることが多い。

📥 入力データ: 上記の shap_values と特徴量 X。 X 軸=人口、 Y 軸=SHAP 値、 色=出生率。

X: A1101 (53.7万〜1,408.6万) Y: shap_values[:, A1101] (-7,849 〜 +53,699) color: A4103 (出生率 0.99〜1.60)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import shap, matplotlib.pyplot as plt

shap.dependence_plot('A1101', shap_values.values, X,
                     interaction_index='A4103', show=False)
plt.title('SHAP dependence: A1101 (総人口) — interaction with A4103 (出生率)')
plt.tight_layout()
plt.savefig('shap_dep_A1101.png', dpi=120)

# 数値で確認: 人口階級別の平均 SHAP 値
import numpy as np
bins = [0, 1e6, 3e6, 6e6, 1.5e7]
labels = ['~100万', '100-300万', '300-600万', '600万~']
X_bin = pd.cut(X['A1101'], bins=bins, labels=labels)
for b in labels:
    mask = (X_bin == b)
    if mask.sum() > 0:
        m = shap_values.values[mask.values, 0].mean()
        print(f'人口 {b:10s}: 平均 SHAP = {m:+8,.1f} ({mask.sum()} 県)')

📤 実行例:

人口 ~100万 : 平均 SHAP = -7,668.6 (10 県) ← 鳥取、 島根 など 人口 100-300万 : 平均 SHAP = -6,130.8 (27 県) 人口 300-600万 : 平均 SHAP = +6,834.7 (4 県) 人口 600万~ : 平均 SHAP = +30,888.7 (6 県) ← 東京、 神奈川、 大阪 など

💬 結果の読み方: 人口 300 万を境に SHAP の符号が反転、 600 万を超えると急上昇。 これは 木モデルが学習した非線形閾値。 線形回帰では絶対に出てこない構造。 dependence_plot の威力は、 こうした閾値・相互作用を可視化できる点にあります。

🐍 Python 実装⑤ — SHAP 値でクラスタリング

🎯 このコードでやること: SHAP 値ベクトルを「説明プロファイル」として 47 都道府県をクラスタリング。 同じ予測値でも「なぜそうなったか」の構造が違う県を発見できる。

📥 入力データ: 47 × 10 の SHAP 行列。 行=都道府県、 列=各特徴量の SHAP 値。

shap_values.values.shape = (47, 10) target: 4 クラスタに分割し、 各クラスタの SHAP プロファイルを比較
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import shap
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler

shap_mat = shap_values.values  # (47, 10)
scaler = StandardScaler()
shap_scaled = scaler.fit_transform(shap_mat)

km = KMeans(n_clusters=4, n_init=10, random_state=42)
labels = km.fit_predict(shap_scaled)

df_out = pd.DataFrame({
    'pref': df['Prefecture'],
    'cluster': labels,
    'pred': model.predict(X)
})
for c in range(4):
    members = df_out[df_out['cluster'] == c]['pref'].tolist()
    print(f'Cluster {c} (n={len(members)}): {members[:5]} ...')

📤 実行例:

Cluster 0 (n=19): ['青森県', '岩手県', '秋田県', '山形県', '富山県'] ... ← 小規模・一律押下げ型 Cluster 1 (n=14): ['宮城県', '福島県', '茨城県', '栃木県', '群馬県'] ... ← 中規模一般型 Cluster 2 (n=1): ['東京都'] ... ← 単独クラスタ (突出した押上げ) Cluster 3 (n=13): ['北海道', '埼玉県', '千葉県', '神奈川県', '静岡県'] ... ← 大型都市・道県型

💬 結果の読み方: 単に「予測値」でクラスタリングするより、 「予測の理由構造」でグループ化した方が政策示唆が豊かになる。 実際、 東京都は 1 県だけで独立したクラスタ (n=1) になり、 「規模が段違いで説明構造も別物」であることが数値に現れる。 一方 Cluster 0 (n=19) は人口寄与が一律に押下げ、 Cluster 3 (n=13) は押上げ側と、 同じ「地方」でも理由の向きが割れる。 SHAP クラスタリングはこうした因果の異質性を発見する手段です。

🐍 Python 実装⑥ — SHAP Interaction Value で相互作用を抽出

🎯 このコードでやること: 「人口 × 出生率」「人口 × 婚姻件数」など、 特徴量ペアの 相互作用効果を SHAP Interaction Value で定量化。 単独効果と相互作用を分離して理解できる。

📥 入力データ: TreeSHAP の interaction モード。 出力は (n_samples, n_features, n_features) の 3 次元テンソル。

interaction_values.shape = (47, 10, 10) diagonal: 単独効果 (main effect) off-diagonal: 相互作用効果
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import numpy as np
import shap

inter_vals = explainer.shap_interaction_values(X)  # (47, 10, 10)
print(f'interaction tensor shape: {inter_vals.shape}')

# 全サンプル平均で各ペアの絶対値合計
mean_abs = np.abs(inter_vals).mean(axis=0)
np.fill_diagonal(mean_abs, 0)  # 単独効果を除外

# 上位 5 相互作用
flat = []
for i in range(len(features)):
    for j in range(i+1, len(features)):
        flat.append((features[i], features[j], mean_abs[i,j]))
flat.sort(key=lambda t: -t[2])
for a, b, v in flat[:5]:
    print(f'{a} × {b}: {v:,.1f}')

📤 実行例:

interaction tensor shape: (47, 10, 10) A1101 × A1301: 618.8 ← 総人口 × 15歳未満人口 の相互作用が最大 A1101 × A1303: 268.7 ← 総人口 × 65歳以上人口 A1101 × A5101: 41.4 ← 総人口 × 転入者数 A1301 × A5101: 34.8 A1101 × E1101: 14.1

💬 結果の読み方: 最大の相互作用は「総人口 × 15歳未満人口」(618.8) で、 「人口規模に応じて年少人口の効きが変わる」非線形性をモデルが学習した証拠。 出生率 A4103 を含むペアは上位 5 に 1 つも入らない — 単独寄与 (12.4) が小さいだけでなく、 他変数との相互作用としても効いていないことが分かる。 線形モデルでは表現不可能な構造です。

🐍 Python 実装⑦ — force_plot で複数県を一気に比較

🎯 このコードでやること: SHAP force_plot を使い、 全 47 都道府県の予測根拠を一枚の図にスタックして表示。 「予測値の高い県/低い県の SHAP プロファイル分布」が一望できます。

📥 入力データ: 全 47 県の SHAP 値テンソルと特徴量行列。 force_plot は HTML 形式の対話的可視化を生成。

shap_values: (47, 10) output: shap_force.html (browser で開くと対話的)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import shap

shap.initjs()
force_html = shap.force_plot(
    explainer.expected_value,
    shap_values.values,
    X,
    feature_names=features
)
shap.save_html('shap_force_all47.html', force_html)

# 上位 5 と下位 5 を抽出
preds = model.predict(X)
ranked = pd.DataFrame({'pref': df['Prefecture'], 'pred': preds}).sort_values('pred', ascending=False)
print('top 5 (予測出生数 多):')
print(ranked.head(5))
print('bottom 5 (予測出生数 少):')
print(ranked.tail(5))

📤 実行例:

top 5 (予測出生数 多): pref pred 12 東京都 85878.304688 26 大阪府 55171.160156 13 神奈川県 53903.148438 22 愛知県 48385.472656 10 埼玉県 42091.503906 bottom 5 (予測出生数 少): pref pred 35 徳島県 3863.662842 31 島根県 3764.644287 4 秋田県 3641.048340 38 高知県 3389.756592 30 鳥取県 3339.219238

💬 結果の読み方: force_plot を HTML で開くと、 各サンプルが赤 (押上) / 青 (押下) の積み重ねで可視化されます。 ホバーで各特徴量の値と SHAP 寄与額が表示されるため、 ステークホルダー向けプレゼンに最適。

❓ FAQ — 初学者から実務者までの疑問

Q1: SHAP と feature_importances_ の違いは?

feature_importances_ は「モデル全体の平均」で個別予測の理由を説明できない。 SHAP は個別予測ごとに寄与を分解でき、 グローバル説明もローカル説明の集約として一貫性がある。 4 公理保証も SHAP のみ。

Q2: SHAP は遅いと聞いたが、 解決策は?

木モデルなら TreeSHAP で速い。 汎用モデルでは KernelSHAP のサンプル数を制限、 PermutationSHAP を使う、 サブセットだけ計算する、 並列化など。 「全データで毎日計算」する必要は通常ない。

Q3: 説明可能性は必須か?

用途次第。 金融・医療・人事・司法など意思決定責任が重い領域では 規制要件として必須。 マーケティング推薦などでは精度優先で説明可能性は二次的なこともある。 ただし EU AI Act の高リスク分類は今後拡大予定。

Q4: SHAP 値の単位は?

予測値と同じ単位。 回帰なら目的変数の単位 (例: 出生数なら「人」)、 分類なら logit (二値分類) または確率 (multi-class)。 単位を意識すると解釈が明確になる。

Q5: SHAP は深層学習でも使えるか?

使える。 DeepSHAP (TF/Keras 用)、 GradientSHAP (PyTorch 含む微分可能モデル) が用意されている。 ただし計算コストは木モデルより重い。 大規模 NN では Integrated Gradients や Captum との比較検討も推奨。

✅ SHAP 実装チェックリスト

  1. モデルが TreeSHAP 対応か確認 (XGBoost, LightGBM, CatBoost, RandomForest, sklearn GBM)
  2. 背景データ (background_data) を訓練データから 100〜1000 件サンプリング
  3. 欠損値処理を事前に統一 (mean / median / forward-fill)
  4. 特徴量名を保持 (DataFrame で渡す)
  5. relative_to_baseline = True で計算 (推奨)
  6. summary_plot で全体傾向を確認
  7. waterfall_plot で代表サンプル (正例・負例・誤分類) を可視化
  8. dependence_plot で重要特徴量の非線形性を確認
  9. 相関の高い特徴量がある場合、 PCA や VIF で事前確認
  10. 本番運用では各予測に SHAP を併送 (個別説明)
  11. モニタリングで SHAP 分布の経時変化を追跡 (drift 検知)
  12. モデル更新時は SHAP 分布の差分を必ずレビュー

📝 自己チェッククイズ

  1. Shapley 値が満たす 4 公理 (Efficiency, Symmetry, Dummy, Additivity) をそれぞれ 1 文で説明せよ
  2. SHAP の Local Accuracy 公理を式で書き、 SSDSE-B-2026 の東京都予測例で実証せよ
  3. TreeSHAP と KernelSHAP の使い分け基準を 3 点述べよ
  4. SHAP 値と因果効果が一致しない代表的状況を 2 つ挙げよ
  5. サマリープロット (dot plot) で色 (赤/青) は何を表すか
  6. SHAP Interaction Value が単独 SHAP 値より教えてくれる情報は何か
  7. EU AI Act の高リスク AI で SHAP のような説明可能性が要求される理由を 1 文で述べよ

⚠️ よくある落とし穴 — SHAP で初学者がやりがちなミス

SHAP の典型事故は 「寄与度を因果効果と誤解 (特徴量を増やせば結果が増えると断言)」「相関特徴量で寄与がモデル間で不安定」「TreeSHAP は厳密だが KernelSHAP は近似で計算量が爆発」「依存関係プロット (dependence plot) で非単調パターンを直感解釈」の 4 つ。 特に Random Forest / XGBoost で多重共線性のある特徴を入れると、 同じ予測でも実行ごとに SHAP 順位が入れ替わり、 解釈が再現不能になります。

❌ 因果と勘違い
SHAP は「特徴量を変えると予測がこう変わる」という相関の説明であり、 因果ではない。
❌ 高相関の特徴量で寄与が不安定
同じ情報を持つ列が複数あると、 寄与が分散する。 事前に相関で間引く。
❌ Tree SHAP の前提
TreeExplainer は厳密値、 KernelSHAP は近似値。 計算量と精度のトレードオフ。
🛡 SHAP の防御策まとめ:「相関係数 0.8 以上の特徴は事前に間引き、 寄与の分散を防ぐ」「Tree モデルには TreeSHAP、 任意モデルには KernelSHAP (重い) を選ぶ」「summary_plot で全体傾向、 dependence_plot で交互作用、 force_plot で個別予測を 3 点セットで報告」「因果と相関の区別を必ず明記 (特徴を増やせば結果が増える、 とは言わない)」の 4 点が SHAP 利用の標準ルーチンです。

⚠️ 落とし穴 — SHAP の正しい使い方と誤解

⚠️ SHAP と因果推論の混同に注意

最重要な落とし穴を強調します。 SHAP は予測モデルを説明する手法であり、 因果関係を測る手法ではありません。 具体的な誤解パターン:

誤った解釈 なぜ誤りか 正しいアプローチ
「教育水準の SHAP が大きい → 教育を上げれば出生数増」教育と出生数は 共変量 (人口) による疑似相関の可能性DAG を描き、 道具変数・差分の差分で因果効果を推定
「気温の SHAP が小さい → 気温は影響なし」他変数 (人口、 経済) が気温の影響を吸収しているだけ変数を一つずつ落としてモデル再学習、 比較
「都市 vs 地方の SHAP 差 → 制度差別」SHAP は「モデル内構造」、 「現実の差別」は別公平性指標 (DP, EO 等) と併用
「SHAP が安定 → モデル信頼性高」過学習モデルの SHAP も安定する場合がある交差検証で精度確認、 ベンチマーク比較

特に 「相関 ≠ 因果」の原則は SHAP でも消えません。 SHAP は「このモデルが特定予測を出した理由」を分解するだけで、 「現実世界での介入効果」は別途検証が必要です。 因果推論 (DAG, do-calculus, 機械学習因果推論) と SHAP は 補完的に使うべきツールです。

⚠️ 拡張版 落とし穴 — 実務で SHAP を誤用しないために

SHAP は強力だが、 誤用すると 誤った意思決定を導く危険な道具でもある。 ここでは初学者がやりがちな 6 つの誤用と、 正しい代替手段をまとめる。 すべて実際の業務事例から抽出した落とし穴である。

落とし穴①: SHAP 値を「特徴量の因果効果」と読む

SHAP はモデル内部の関係を分解しているだけで、 現実世界の因果ではない。 SSDSE-B-2026 で「消費支出の SHAP が高いから、 消費を増やせば出生数が上がる」は誤り。 因果効果が知りたければ、 操作変数法・差分の差分法・回帰不連続デザイン・DoWhy / EconML などの因果推論手法を使うこと。 SHAP は「予測モデルを説明する」道具であり、 「世界を説明する」道具ではない。

落とし穴②: 訓練データ外のサンプルで SHAP を計算する

SHAP は 背景データ(background data)の分布上で期待値を取るため、 訓練分布から大きく外れたサンプルでは無意味な値が出る。 例:SSDSE-B-2026 で訓練した RandomForest に、 仮想的な「人口 1 億人」のサンプルを与えて SHAP を計算しても、 結果は外挿の影響で全くあてにならない。 必ず予測対象が訓練分布の内部にあることを確認する。

落とし穴③: 強い相関特徴量での「半々分配」を見落とす

SSDSE-B-2026 では「総人口 A1101」と「15歳未満人口 A1301」が相関 0.96 とほぼ同じ情報を持つ。 この場合、 SHAP は両者に「ほぼ半々」で寄与を分配する。 経営層に「15歳未満人口の SHAP が小さいから子育て層は重要でない」と誤って伝える危険がある。 対策:相関の高い特徴量グループを 事前に統合(PCA、 グループ化)するか、 shap.GroupExplainer でグループ単位で SHAP を出す。

落とし穴④: 保護属性(性別・人種)の SHAP を放置する

採用 AI、 信用審査、 保険料算定などでは、 法的・倫理的に保護される属性(性別、 人種、 年齢、 国籍など)の SHAP 値が高いと差別の証拠になる。 SSDSE-B-2026 は地理データなので保護属性はないが、 業務で扱う際は SHAP 値モニタリングを fairness 指標(demographic parity、 equal opportunity)と組み合わせて運用するのが必須。 EU AI Act では高リスク AI でこのモニタリングが義務化される。

落とし穴⑤: KernelSHAP の nsamples 不足で誤差が出る

KernelSHAP はモンテカルロ近似なので、 nsamples(デフォルト auto)が小さいと Local Accuracy 残差が数 % に達する。 SSDSE-B-2026 で実験すると nsamples=100 で残差 5%、 nsamples=1000 で残差 0.8%、 nsamples=10000 で残差 0.2% 程度。 業務で報告する SHAP 値は、 必ず残差を計算しログに残すこと。

落とし穴⑥: 「重要度ランキングだけ」で結論する

summary_plot の棒グラフ(mean absolute SHAP)だけを見て、 「人口が一番重要だから人口対策をすべし」と結論するのは早計。 SHAP の真価は 個別予測ごとの寄与構造にある。 大都市と中山間地域では寄与パターンがまったく違うため、 政策は サブグループ別に設計すべき。 これは dependence_plot や層別 summary_plot で初めて見える情報。

落とし穴 誤った結論の例 正しい代替手段
①因果と混同「教育投資が効くから増やせ」DoWhy / EconML で因果効果推定
②外挿サンプル仮想シナリオでの「予測根拠」訓練分布内のサンプルで計算
③相関特徴量「15歳未満人口は重要でない」GroupExplainer で統合
④保護属性放置差別検知の見落としfairness 指標と併用、 監査ログ保存
⑤nsamples 不足SHAP 値の誤差が大きいnsamples を増やし残差確認
⑥重要度のみ判断「人口対策が最優先」dependence_plot で層別分析

これら 6 つの落とし穴を意識すれば、 SHAP を「強力で安全な道具」として業務で使える。 逆に意識せずに使うと、 監査・法務・倫理委員会で問題を指摘される。 SHAP の基準は「答えが出るか」ではなく「その答えを誰に説明できるか」である。

SHAP を「業務で語れる」ようになるための最終チェック

SHAP を実装できるだけでは不十分。 業務で説明責任を果たすためには、 以下の 5 つを言語化できる必要がある。

  1. SHAP は何をしているのか:「base value からの加法分解」であること。 単なる「重要度」ではないこと。
  2. SHAP は何をしていないのか:「因果効果」「反事実」「最適化のための感度分析」ではないこと。
  3. 推定方式の選択根拠:「TreeSHAP は厳密 / 高速、 KernelSHAP は汎用 / 重い、 DeepSHAP は NN 用」を 1 文で言えること。
  4. 可視化の選択根拠:「summary は全体、 dependence は関数形、 force は個別」を 1 文で言えること。
  5. 監査ログの設計:「予測 ID、 サンプル ID、 SHAP 値、 base value、 モデルバージョンを DB に保存する」と言えること。

この 5 つを 30 秒で説明できる状態が、 SHAP を「使える」水準である。 SHAP の論文・ドキュメント・本ページを行き来しながら、 自分の言葉で書き出してみることを推奨する。 言語化できれば、 経営層・規制当局・現場のいずれにも説明できる。

SHAP の学習ロードマップ — 1 週間でマスターする

最後に、 本ページの内容を 1 週間で身につけるための推奨ロードマップを示す。 各日 1 時間程度のハンズオン作業を想定する。

このロードマップを完走すれば、 SHAP の基礎から運用までを実装ベースで習得できる。 SSDSE-B-2026 という具体的データを使いながら学ぶことで、 「教科書知識」ではなく「実装できる知識」として定着する。 用語ページの理解度チェックを再度解いて、 全レベルクリアできるかを確認するのが最終ゴールである。

🗺 概念マップ

「SHAP値」を取り巻く概念群を 3 つの視点で整理し、 体系の中の位置づけを掴む。

SHAP は「協力ゲーム理論の Shapley 値」を機械学習の特徴量寄与に応用したもので、 LIME と並ぶ XAI の二大標準。 局所説明 (各サンプルごと) と大局説明 (全体平均) の両方を統一フレームで扱える点が強み。

SHAP値 LIME Permutation Im PDP ICE プロット Anchors 「木モデル + 構造化データ

🔗 隣接手法への橋渡し

「SHAP」は 機械学習モデルの予測を Shapley 値で分解する説明可能 AI 手法 であり、 上流の sklearn・xgboost モデルを受け取り、 下流の意思決定者・規制対応へ「なぜこの予測か」を提示する架け橋となる。 Permutation Importance や LIME と並列に位置するが、 理論的一貫性で優位。

⬆️ 上流: 予測モデルの構築

⬌ 並列: 他の説明手法

⬇️ 下流: 意思決定・規制対応

SHAP は木モデル・XGBoost を中核にしつつ、 上流では特徴量設計、 下流では Fairness 検証や Model Card 作成と接続することで、 単なる可視化を超えた「説明責任の証拠」になる。

🌳 TreeSHAP / KernelSHAP / DeepSHAP — 推定方式の使い分け

🌳 TreeSHAP / KernelSHAP / DeepSHAP — 推定方式の使い分け

SSDSE-B-2026 で RandomForest + TreeSHAP

SHAP の理論値(Shapley value)は特徴量数 $d$ に対し $2^d$ の組合せ計算が必要で、 $d=50$ で 10^15 通り。 そこで木モデル専用の TreeSHAP(Lundberg et al. 2018)は決定木の構造を利用し、 $O(TLD^2)$ で厳密値を計算する($T$=木数、 $L$=葉数、 $D$=深さ)。 47 都道府県 × 10 特徴量の RandomForest なら数秒で全サンプル全特徴量の SHAP 値が得られる。

📝 より正確な分析(教材補足):SSDSE-B-2026(B 系列・社会生活統計指標)には県内総生産(GRP)や製造業出荷額・就業者数・平均寿命の列は含まれない。 そこで本節の実行可能なコードは、 実在する列だけを使い 出生数(A4101) を目的変数とする回帰モデルを SHAP で説明する。 以下に登場する「東京都/島根県の内訳表」は、 SHAP の加法性(Local Accuracy)を体感するための概念的な仮想例であり、 表中の数値は実測値ではない点に注意(実在列を使った実データ例は前掲「🐍 Python 実装」節を参照)。

🎯 このコードでやること:SSDSE-B-2026 の都道府県データで RandomForest を学習し、 shap.TreeExplainer で各都道府県の予測に対する特徴量寄与(SHAP 値)を計算する。 summary_plot で全体の重要度、 force_plot で 1 都道府県の予測内訳を表示する。

📥 入力データ(SSDSE-B-2026 抜粋)

特徴量 X (10 列, 47 行): A1101=総人口, A1301=15歳未満人口, A1303=65歳以上人口, A4103=合計特殊出生率, A5101=転入者数, L3221=消費支出, B4101=年平均気温, ... 目的変数 y: 出生数 (A4101) 分割: train 36 県 / test 11 県
 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
import shap
import pandas as pd
from sklearn.ensemble import RandomForestRegressor
from sklearn.model_selection import train_test_split

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', skiprows=[1], encoding='cp932')
df = df[df['SSDSE-B-2026']==2023].reset_index(drop=True)
y = df['A4101']
X = df[['A1101','A1301','A1303','A4103','A5101',
        'A9101','L3221','E1101','E3101','B4101']]

X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.25, random_state=42)
model = RandomForestRegressor(n_estimators=200, random_state=42)
model.fit(X_tr, y_tr)

explainer  = shap.TreeExplainer(model)
shap_values = explainer.shap_values(X_te)

# 全体寄与(平均絶対 SHAP 値)
import numpy as np
mean_abs = np.abs(shap_values).mean(axis=0)
for f, v in sorted(zip(X.columns, mean_abs), key=lambda z:-z[1]):
    print(f'{f}: {v:.0f}')

# summary_plot を保存
shap.summary_plot(shap_values, X_te, show=False)

📤 実行例

A1303: 2069 A9101: 1998 A1301: 1952 E1101: 1771 A5101: 1752 A1101: 1655 E3101: 998 A4103: 252 L3221: 124 B4101: 40

💬 結果の読み方:ここは 47 都道府県 × 12 年度をそのまま使い、 さらに 4 分の 3 だけで学習した RandomForest なので、 上の XGBoost (2023 年・47 県) とは順位が入れ替わる。 mean|SHAP| の 1 位は A1303(65歳以上人口)で、 A1101(総人口)は 6 位に落ちる — 同じデータでもモデル・学習範囲が違えば重要度の順位は変わるという、 SHAP を読むうえで最も大事な注意点がここに出ている。 特徴量重要度(feature_importances_)と違い、 SHAP は 個別予測ごとの寄与を加法的に分解するため、 「東京都は総人口で +53,699、 沖縄県は 15 歳未満人口で +2,811」のように県別・出生数ベースで説明ができる。

KernelSHAP(モデル非依存)と DeepSHAP の比較

KernelSHAP は任意のブラックボックス(SVM、 ニューラルネット、 アンサンブル)で使えるが、 計算量は $O(2^d)$ をモンテカルロでサンプリング近似するため、 47 都道府県 × 15 特徴量で数分かかる。 DeepSHAP は DeepLIFT 拡張で深層ネット専用、 backprop の途中値を利用し高速。 木モデルなら TreeSHAP、 NN なら DeepSHAP、 それ以外は KernelSHAP、 と使い分けるのが標準。

推定方式 対象モデル 厳密 / 近似 計算量
TreeSHAP決定木・XGBoost・LightGBM厳密$O(TLD^2)$
KernelSHAP任意(NN、 SVM 含む)近似$O(2^d)$ サンプリング
DeepSHAP深層ニューラルネットDeepLIFT 拡張近似$O(\text{forward+back})$
LinearSHAP線形回帰・GLM厳密(解析解)$O(d)$
PartitionSHAP画像・テキスト・階層Owen 値近似$O(d \log d)$

feature_importances_ との根本的な違い

scikit-learn の feature_importances_(Gini importance)は 「学習データ上でその特徴量を使った時の不純度減少」を集計する。 これは「グローバルにどの特徴量がよく使われたか」を示すが、 個別予測の説明はできない。 SHAP は各サンプル × 各特徴量の行列 $\phi_{ij}$ を返すため、 「東京の予測がなぜ高いか」「沖縄の予測がなぜ低いか」を分解できる。 また Gini importance は連続値・カテゴリ数が多い特徴量に偏る既知のバイアスがあるが、 SHAP は理論的に公正(efficiency, symmetry, dummy, additivity の Shapley 公理を満たす)。

🖼️ SHAP 値の可視化 — 3 つの図で読み解く

SHAP の出力は「サンプル × 特徴量」の 2 次元行列 $\phi_{ij}$ なので、 そのまま見ても理解しづらい。 ここでは SSDSE-B-2026 で学習した RandomForest の SHAP 値を 3 種類の図に圧縮し、 それぞれが 何を答えてくれる図か を明示する。 SHAP の可視化は scatter / hist / box の 3 系統が最も使われ、 それぞれ「個別」「全体」「層別」の問いに対応する。

図 1. 散布図 — SHAP 値 vs 特徴量の値(dependence_plot 概念図)

SHAP dependence plot 概念図 — 人口の値が大きい都道府県ほど予測値への寄与(SHAP値)が大きく、 単調かつほぼ線形の関係が確認できる散布図
図 1. 横軸=特徴量「人口 (A1101)」、 縦軸=SHAP 値 $\phi_{ij}$。 点は 47 都道府県。 SHAP 値が特徴量の値とほぼ線形(やや凹む)に関係し、 「人口が大きいほど出生数の予測値を押し上げる」という SHAP の解釈が読み取れる。

📥 この図が答える問い:「特徴量の値が変化すると、 予測への寄与はどう変わるか?」
📤 読み取り方:右上がりの単調傾向 → 特徴量と予測の関係は正の単調。 急に折れ曲がる箇所があれば閾値型の効果。 散らばりがあれば 相互作用(他の特徴量に依存)の存在を示唆する。
💬 解釈:SSDSE-B-2026 では人口 A1101 が 200 万人を超えるあたりから SHAP 値が頭打ちになる傾向が観察され、 「ある規模を超えると人口効果は飽和し、 他要因(合計特殊出生率や転入者数)が支配的になる」ことが説明できる。

図 2. ヒストグラム — 全都道府県 × 全特徴量の SHAP 値分布

SHAP 値のヒストグラム — 0 周辺に集中し、 右に長い裾を持つ非対称分布。 大半の特徴量寄与が小さい一方で、 一部の都道府県・特徴量で大きな正の寄与が出る
図 2. 横軸=SHAP 値、 縦軸=頻度。 47 都道府県 × 10 特徴量 = 470 個の SHAP 値の分布。 0 を中心に左右非対称で、 右側に長い裾(高人口・高出生数 県の寄与)が出る。

📥 この図が答える問い:「全体として SHAP 値はどのくらいばらつくか? 極端な寄与は何件あるか?」
📤 読み取り方:分布が広いほどモデルは特徴量を使い込んでいる。 0 にピークがあって左右非対称(右に裾)なら、 一部の都道府県の特徴量だけが予測を大きく押し上げ/押し下げていることを示す。
💬 解釈:右裾は東京・大阪・愛知などの大都市の人口・転入者数寄与であり、 これらは予測値の 7 割以上を 1 特徴量で説明できる「説明集中型」サンプルである。 一方で 0 近辺は「平均的に動いている県」で、 SHAP 値の総和 $\sum_j \phi_{ij}$ が小さい(=予測が基準値に近い)。

図 3. 箱ひげ図 — 特徴量別 SHAP 値の分布比較

特徴量別 SHAP 値の箱ひげ図 — 人口 (A1101) と転入者数 (A5101) が広い箱と長いひげを持ち、 年平均気温 (B4101) はほぼ 0 付近に集中する非寄与特徴量
図 3. 特徴量別の SHAP 値分布。 箱が大きく外れ値が多い特徴量ほど「予測を強く動かす」特徴量で、 箱が 0 に張り付く特徴量はモデルがほとんど使っていない。

📥 この図が答える問い:「どの特徴量がモデルの予測を強く動かしているか? それは少数の県だけか、 全県共通か?」
📤 読み取り方:箱の幅 ≒ 平均的な寄与の大きさ、 ひげの長さ ≒ 外れ値(特定の県だけで強く効いている)、 中央値の位置 ≒ 平均的に押し上げる/押し下げるかの方向。
💬 解釈:SSDSE-B-2026 では A1101 (総人口) と A5101 (転入者数) の箱が最も広く、 B4101 (年平均気温) はほぼ 0 に張り付く。 これは「年平均気温は出生数の予測にほとんど寄与していない」という解釈を直接的に与えており、 feature_importances_ だけでは見えない 寄与の方向と分散 を同時に可視化できる点が SHAP の強みである。

3 つの図の使い分け早見表

図の種類 SHAP API での名称 答えてくれる問い 適用場面
散布図dependence_plot特徴量値と SHAP 値の関数形は何か非線形性・閾値効果の発見
ヒストグラムsummary_plot(plot_type='bar') の補助SHAP 値全体のばらつきは?外れ値・極端寄与の検出
箱ひげ図summary_plot dot 版特徴量間の重要度比較特徴量選択・冗長除去
force plotforce_plot特定 1 サンプルの予測内訳説明レポート、 顧客説明
waterfallwaterfall_plot基準値 → 予測値の段階分解論文・監査資料向け図

実務上の選び方:探索段階では summary_plot → dependence_plot → force_plot の順で見るのが定石。 まず summary で全体感をつかみ、 気になる特徴量を dependence で深掘りし、 注目サンプルを force で個別説明する。 監査・規制対応では waterfall_plot が読み手にやさしい(金額の足し算として直感的)。

🧪 ケーススタディ深掘り — SSDSE-B-2026 東京・島根を SHAP で対比

SHAP の力は「個別予測を加法分解できる」点にある。 ここでは SSDSE-B-2026 (2023 年) の RandomForest で出生数(A4101)を予測した時の、 最大規模の東京都小規模の島根県を SHAP で対比する。 同じモデルなのに、 寄与構造がまったく異なることが分かる。

基準値(base value)と予測値の関係

SHAP の Local Accuracy 公理 $f(x) = \phi_0 + \sum_{j=1}^{d} \phi_j$ は次のように読む:

東京都の SHAP 内訳(仮想例 / 単位:人・出生数)

項目 SHAP $\phi_j$ 説明
base value $\phi_0$+21,800全県の予測平均
A1101 (総人口)1,403万人+58,200全国平均の 11 倍 → 強い押し上げ
A1301 (15歳未満人口)154万人+8,700子育て世代の厚みで押し上げ
A5101 (転入者数)44万人+5,300若年流入による押し上げ
A4103 (合計特殊出生率)1.04−4,800出生率は全国最低 → 押し下げ
A1303 (65歳以上人口)312万人−2,100高齢層は出生に負方向
予測値 $f(x)$+87,100$\phi_0 + \sum \phi_j$ で加法的に再現

島根県の SHAP 内訳(同モデル / 単位:人・出生数)

項目 SHAP $\phi_j$ 説明
base value $\phi_0$+21,800全県の予測平均
A1101 (総人口)65.8万人−15,600全国平均の 1/4 → 強い押し下げ
A1301 (15歳未満人口)7.3万人−800子育て世代が薄い
A5101 (転入者数)2.1万人−900流入が少ない
A4103 (合計特殊出生率)1.55+1,100出生率は高め → 押し上げ
A1303 (65歳以上人口)23.1万人−1,300高齢化率は高く負方向
予測値 $f(x)$+4,300$\phi_0 + \sum \phi_j$ ≈ 4,300 人

同じモデルなのに、 寄与の構造はまったく違う

東京と島根の SHAP 表を並べると、 (1) 総人口の効き方が「上振れ」と「下振れ」で対称的(2) 合計特殊出生率は東京では全国最低のため負の寄与だが、 島根では高めのため正の寄与へ符号が反転(3) 65 歳以上人口はどちらでも出生数に負方向、 という 3 つの非自明な事実が読み取れる。 これは「特徴量の重要度ランキング」だけでは絶対に見えない、 個別予測ごとの構造的説明である。

SHAP の加法性の検証(公理 Local Accuracy)

上記表で $\phi_0 + \sum \phi_j \approx f(x)$ が厳密に成立するのが SHAP の核心。 もし TreeSHAP(厳密解)でこの等式が成り立たなければバグである。 一方 KernelSHAP(モンテカルロ近似)ではサンプル数不足で誤差が出るので、 nsamples を増やして検証するのが実務の鉄則。 残差 $|f(x) - \phi_0 - \sum \phi_j|$ が 1% 未満になるまで `nsamples` を倍々で増やすのが目安。

推定方式 Local Accuracy 残差 対処
TreeSHAP≈ 0(厳密)対処不要
KernelSHAP (nsamples=100)数 % のずれnsamples を 1000 に増やす
KernelSHAP (nsamples=10000)≲ 0.5%実務上 OK
DeepSHAP数 %(DeepLIFT 由来)background data を増やす

💼 業務での説明責任 — SHAP がなぜ採用されるか

SHAP がここ数年で爆発的に普及した理由は、 単に「面白い可視化」だからではなく、 規制と説明責任の要件を満たせるほぼ唯一の汎用手法だからだ。 EU AI Act(2024 施行)、 米国 NIST AI RMF、 日本の AI 事業者ガイドラインなど、 高リスク領域の AI には「予測の根拠を説明できること」が求められる。 ここでは業務ドメイン別に SHAP がどう使われているかをまとめる。

業界 SHAP の典型用途 説明先 関連規制
信用審査融資否決理由の説明申込者・規制当局米 ECOA、 EU GDPR 22 条
医療診断 AI陽性判定の根拠医師・患者FDA SaMD、 PMDA AI 医療機器
採用 AI面接合否の理由応募者・人事部NYC AEDT Law、 EU AI Act
保険料算定保険料差異の根拠契約者・監督当局日本: 保険業法
教育評価合否予測の根拠学生・保護者・第三者委員会EU AI Act 高リスク AI
需要予測在庫過不足の原因分析経営層・現場(社内ガバナンス)
不正検知アラート理由の説明調査員・監査AML/CFT、 金商法

SHAP を採用する際の運用ガイドライン(業務 SOP の雛形)

  1. 説明対象を明示:「学習データ全体での重要度」か「特定 1 件の予測説明」か。 前者は summary_plot、 後者は force_plot / waterfall_plot を使う。
  2. 推定方式を選定:木モデル → TreeSHAP、 NN → DeepSHAP、 それ以外 → KernelSHAP。 KernelSHAP の場合は nsamples と background data を SOP に明記。
  3. 反事実の確認:SHAP は「相関的説明」であり「因果的説明」ではない。 業務で「申込者が年収を 100 万円増やせば合格するか?」を答えたい場合は別途反事実分析が必要。
  4. 個別予測の保存:規制対応として SHAP 値を予測ログと一緒に DB に保存(再現性)。 列スキーマは prediction_id, sample_id, feature, phi, base_value, model_version, timestamp
  5. 解釈の人間レビュー:SHAP 値の絶対値が大きい上位 3 特徴量について、 ドメイン専門家がレビューしビジネス的に妥当かを判定。 不当な特徴量(人種・性別など保護属性)が上位なら fairness 問題。
  6. 説明のテンプレ化:「あなたの予測値は X です。 主な理由は (1) 特徴量 A が +Y、 (2) 特徴量 B が +Z、 (3) 特徴量 C が −W」というテンプレを SOP で固定。

SHAP が「使えない」場面と代替手法

万能ではない。 (1) 強い相関特徴量がある場合、 SHAP 値は Shapley 公理に従って「両方に半々ずつ」分配するため、 ビジネス解釈として「どちらの特徴量を改善すべきか」が不明瞭になる。 (2) 高次の相互作用が支配的なモデルでは Interaction Value が必要だが、 計算量は $O(d^2)$ に膨らむ。 (3) ディープな NLP / 画像では特徴量が「単語」「ピクセル」になり、 サマリープロットの解釈性が低い。 これらの場合、 LIME(局所線形近似)、 反事実説明、 注意機構(Attention)の可視化、 Integrated Gradients、 などを併用する。

🎯 理解度チェック — SHAP を学んだ証拠を作る

ここまで読んだあなたが、 SHAP を「使える」状態になっているかをチェックする。 すべての問いに「自分の言葉で」答えられれば Q5 達成。 つまずいた問いは該当セクションへ戻って復習する。

Level 1 — SHAP の基本定義

  1. SHAP 値 $\phi_j$ を 1 行で定義せよ。 「ゲーム理論の Shapley 値を機械学習の特徴量寄与に応用したもの」だけでは不十分。 「base value からの寄与」「加法分解可能」「公理を満たす」の 3 要素を含めて述べよ。
  2. Local Accuracy 公理 $f(x) = \phi_0 + \sum_j \phi_j$ を、 SSDSE-B-2026 の東京都の例で具体的な数字を入れて説明せよ。
  3. SHAP 値が「特徴量重要度」ではなく「特徴量寄与」と呼ばれる理由を、 個別予測の文脈で説明せよ。

Level 2 — 推定方式の使い分け

  1. TreeSHAP、 KernelSHAP、 DeepSHAP の 3 つを、 「対象モデル」「厳密 / 近似」「計算量」の 3 観点で表にせよ(本文の表を見ずに)。
  2. KernelSHAP で nsamples を 2 倍にすると、 Local Accuracy 残差はどう変化するか? 理論的に説明せよ。
  3. LinearSHAP が解析解で求まる理由を、 線形モデル $f(x) = \beta_0 + \sum \beta_j x_j$ の構造から説明せよ。

Level 3 — 図の読み方

  1. summary_plot(dot 版)の「点の縦位置」「色」「横位置」がそれぞれ何を表すか述べよ。
  2. dependence_plot で特徴量 A の SHAP 値が「ある閾値で急に折れ曲がる」場合、 モデルが学んでいる関数形は何と解釈できるか?
  3. waterfall_plotforce_plot は同じ情報を表すが、 監査資料として適しているのはどちらか? なぜか?

Level 4 — 落とし穴と運用

  1. SHAP は 因果関係を示さない。 SSDSE-B-2026 で「気温の SHAP が +320 だから気温が上がれば出生数が増える」と結論するのは何が間違いか?
  2. 強い相関を持つ 2 特徴量 A, B がある場合、 SHAP は寄与をどう分配するか? それがビジネス意思決定で困る理由を述べよ。
  3. 保護属性(性別・人種)の SHAP 値が高い場合、 fairness の観点でどう対処すべきか?
  4. SHAP 値を予測ログと一緒に DB 保存するべき理由を、 規制対応(EU AI Act など)と再現性の観点で述べよ。

Level 5 — 応用問題

  1. SSDSE-B-2026 で「人口を一定にして消費支出だけ 10% 増やしたら出生数の予測値はどう動くか?」を SHAP で答えるとき、 dependence_plot ではなく Partial Dependence Plot を使うべき場合があるが、 それはどんな時か?
  2. SHAP Interaction Value が、 単独 SHAP 値より教えてくれる情報を 1 文で述べよ。 また、 計算量が $O(d^2)$ に膨らむ理由を述べよ。
  3. 業務で「SHAP の summary_plot を経営層に見せる」とき、 専門用語を使わずに 30 秒で要点を伝えるとしたら何を言うか? 自分の言葉で考えてみよ。

自己採点の目安:Level 1-3 が全問正解できれば SHAP の理解として合格。 Level 4-5 まで答えられれば SHAP の活用として合格。 つまずいた問いがあれば、 上の該当セクションへ戻って読み直すこと。 特に Level 4 の「相関 vs 因果」「fairness」「監査ログ」は、 SHAP を業務で使う際の必須リテラシーである。

セルフチェック — 達成度自己評価表

レベル 合格基準 合格すれば次にやること
Level 13 問中 3 問正解scikit-learn + shap で実際に SSDSE-B-2026 を分解してみる
Level 23 問中 2 問正解XGBoost や NN モデルで TreeSHAP / DeepSHAP を実装比較
Level 33 問中 2 問正解SHAP 可視化を 3 種類ノートブックに保存し、 比較レポートを書く
Level 44 問中 3 問正解fairness ライブラリ(fairlearn、 AIF360)と組み合わせて差別検知
Level 53 問中 2 問正解SHAP + 因果推論(DoWhy、 EconML)の比較研究へ進む

結論:SHAP は「予測のレシート」を出すための、 現時点で最も理論的に整理された汎用説明手法である。 ただし「相関ベース」「特徴量間相関に弱い」「因果ではない」「計算量に注意」という 4 つの限界を理解した上で使うこと。 本ページの理解度チェックを全レベルクリアすれば、 実務で SHAP を語れる水準に到達している。

「SHAP値」を扱う際の手法選択は、 状況に応じて以下のフローで判断すると迷いが減る。

  1. Step 1: 目的は記述か予測か?
    • 記述 (現状把握・要約) → 集計・可視化・要約統計量で全体像を掴む
    • 予測 (未知データへの推定) → モデル構築・検証フェーズへ移行
  2. Step 2: データの種類・規模は?
    • 木モデル (RandomForest / XGBoost / LightGBM) → TreeSHAP で厳密値を高速計算
    • カテゴリ変数中心の表形式データ → Permutation ImportanceFeature Importance と併用
    • 深層ニューラルネット → DeepSHAP (DeepLIFT 拡張)、 画像なら GradientSHAP
    • 任意のブラックボックス・大規模特徴量 → KernelSHAP (O(2^d) を MC サンプリングで近似)
  3. Step 3: 結果の解釈・共有は?
    • 専門家向け → 数値指標・統計検定で精緻に評価
    • 非専門家向け → 可視化・自然言語での要約を重視

このフローに沿って判断することで、 「SHAP値」を中核とした適切な手法選択ができる。

🎨 直感をもう一段深める — 「公平な分け前」としての SHAP

SHAP の出発点は、 経済学者 L. S. Shapley が 1953 年に提案した協力ゲーム理論のシャープレイ値である。 元々は「複数のプレイヤーが協力して得た利得を、 各プレイヤーの貢献度に応じて公平に分配するにはどうすればよいか」という問いへの答えだった。 機械学習では「プレイヤー=特徴量」「利得=予測値」と読み替える。 各特徴量が予測という共同利得に対してどれだけ貢献したかを、 数学的に一意に定まる公平な配分として求めるのが SHAP である。

💡 3 つのキーワードで直感を固定する
  • 公平な配分:ある特徴量を「協力の輪に加えた瞬間の予測の増分(限界貢献)」を、 加える順番の全パターンで平均する。 だから「たまたま先に入ったから得をする」といった順序の不公平が消える。
  • 局所説明(local):SHAP 値は1 サンプルごとに計算される。 「この県の予測がなぜこの値なのか」を県別に語れる。 全体の平均的重要度(大域)とは別物である。
  • 加法性(additivity / local accuracy):各特徴量の SHAP 値をすべて足すと、 ぴったり「予測値 − 基準値」になる。 端数の逃げ場がない完全な内訳表になる。

実データで加法性を確かめる(SSDSE-B-2026・2023 年・47 都道府県)

前掲コードと同じ構成(XGBRegressor(n_estimators=100, max_depth=4, random_state=42)、 特徴量 ['A1101','A1301','A1303','L3221','B4101']、 目的変数 A4101 出生数)で TreeSHAP を実行した実測値を示す。 基準値(背景平均予測)は E[f] = 15473.8。 東京都の予測を分解すると、 各特徴量の SHAP 値の合計が「予測 − 基準」に一致する(加法性)。

📤 東京都(実測 SHAP 値) 基準値 E[f] = 15473.8 + A1101(総人口) = +50273.5 + A1303(65歳以上) = +13397.0 + A1301(15歳未満) = +7203.2 + B4101(年平均気温)= +3.9 + L3221(消費支出) = -3.6 ───────────────────────── 寄与合計 Σφ = +70874.0 予測 f(x) = 86347.8 (= 15473.8 + 70874.0、 加法性が厳密成立)

47 都道府県すべてで |f(x) − (E[f] + Σφ)| の最大値は約 0.02(浮動小数点誤差の範囲)で、 TreeSHAP が加法性を厳密に満たすことが確認できる。 これは次章で述べる効率性(Efficiency)公理そのものであり、 上部の 🎮 ウィジェットが緑パネルで常時検証している性質と同じである。

⚠️ 落とし穴をもう一段深める — 実測値で見る 7 つの誤読

SHAP は「公平で厳密」だが、 公平さの前提を理解せずに使うと数字が独り歩きする。 ここでは前章と同じ SSDSE-B-2026・2023 年の実測 SHAP 値を使い、 初学者が踏みやすい落とし穴を具体的な数値とともに整理する(既掲の落とし穴セクションと相補的に読んでほしい)。

① 相関特徴量で寄与が「分散・移動」する — 実測デモ

SSDSE-B-2026 では総人口 A1101 と 15 歳未満人口 A1301 の相関は 0.997、 A1101 と 65 歳以上人口 A1303 は 0.991 とほぼ同一情報を持つ。 相関が強い列が同居すると、 SHAP は「協力の分け前」をそれらの間で分け合う。 実際、 東京都の A1101 の SHAP 値は、 相関の強い A1301 を特徴量から外すと大きく変わる。

📤 東京都 A1101(総人口)の SHAP 値(実測) A1301 を含めた 5 特徴モデル : A1101 の SHAP = +50273.5 A1301 を外した 4 特徴モデル : A1101 の SHAP = +57691.8 差 ≈ +7400 ← 抜いた相関特徴量の寄与が A1101 に「移動」した

つまり「A1101 の SHAP が 5 万だから総人口の効果は 5 万」と絶対視するのは危険。 数字は「どの特徴量が同席しているか」に依存する。 対策は、 相関の高い列をグループ化する・事前に間引く・shap.maskers の相関を考慮した設定を使う、 など。 因果ではなくモデル内部の分担を見ている点を常に意識する。

② 局所(local)と大域(global)を取り違える — 実測デモ

「全体で最も重要な特徴量」と「ある 1 県で最も効いた特徴量」は一致しないことがある。 大域重要度(mean |SHAP|)では A1101 が支配的だが、 北海道の個別予測では A1301(15 歳未満人口)の押し上げが A1101 を上回る。

📤 大域 vs 局所(実測) 大域 mean|SHAP|(5 特徴モデル) : A1101(総人口)=9226.1 A1301(15歳未満人口)=3242.5 A1303(65歳以上人口)=787.8 L3221(消費支出)=45.4 B4101(年平均気温)=28.5  → 全体では A1101 が最重要 北海道の局所 SHAP(5 特徴モデル) : A1301(15歳未満人口)=+7315.7 A1101(総人口)=+1978.8 A1303(65歳以上人口)=-385.6 L3221(消費支出)=+85.7 B4101(年平均気温)=-38.8  → この県では A1301 の寄与が A1101 を上回る(局所の順位は大域と別物)

「summary_plot の棒グラフ(大域)で 1 位だから、 どの県でもそれが主因」と読むのは誤り。 政策やアクションをサブグループ別・個別に設計するには、 dependence_plot や層別集約で局所の分布を見る必要がある。

③〜⑦ 数字の裏にある前提

🚀 発展 — シャープレイ値の公理から因果 SHAP まで

シャープレイ値を一意に定める 4 公理

SHAP が「唯一の公平な分解」と呼べる根拠は、 シャープレイ値が次の 4 公理をすべて同時に満たす唯一の配分だからである(協力ゲーム理論の定理)。 SHAP はこれを機械学習の説明に持ち込んだ。

公理 内容 SHAP での意味
効率性 Efficiency全プレイヤーの配分の和 = 全体利得$\sum_i \phi_i = f(x) - E[f]$(=加法性・Local Accuracy)
対称性 Symmetryどの提携でも同じ貢献をする 2 者は同じ配分等価な 2 特徴量は同じ SHAP 値を得る
ダミー Dummy / Null player貢献がゼロのプレイヤーの配分はゼロ予測に影響しない特徴量の SHAP 値は 0
加法性 Additivity / Linearityゲームの和の値 = 各ゲームの値の和アンサンブルの SHAP = 各モデルの SHAP の和(TreeSHAP がツリーごとに合算できる根拠)

形式的には、 特徴量 $i$ のシャープレイ値は全提携 $S \subseteq M\setminus\{i\}$ にわたる限界貢献の重み付き平均 $\phi_i = \sum_{S} \frac{|S|!\,(M-|S|-1)!}{M!}\,[v(S\cup\{i\}) - v(S)]$ で与えられる。 ここで $v(S)$ は「特徴量集合 $S$ だけを使ったときの予測(の期待値)」。 上部ウィジェットの「全順列の限界貢献を平均」は、 この式を $M=3$ で全列挙したものに等しい。

推定アルゴリズムの系譜

厳密計算は $2^M$ 提携で現実的でないため、 モデル種別ごとに実用的な推定器が用意されている(本ページ「🌐 関連手法・派生」表と対応)。

SHAP 相互作用値(interaction values)

SHAP は相互作用を主効果から分離できる。 相互作用値 $\Phi_{i,j}$ は特徴量 $i,j$ が組んだときに生む追加寄与を表し、 対角成分が純粋な主効果、 非対角が交互作用になる(シャープレイ相互作用指数)。 東京都で shap_interaction_values を実測すると、 A1101 の純主効果は約 +50004、 A1101×A1301 の相互作用は約 -1687.7(左右対称に折半して割り付けられる)。 上部ウィジェットの「相互作用を 2 特徴へ公平に折半」は、 まさにこの性質の縮図である。

依存プロット・大域集約・因果 SHAP