8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

予測AIモデルの解釈性 Part2

Last updated at Posted at 2026-01-25

はじめに

Orbitics株式会社データサイエンス部の上野です。

Part1では、機械学習モデルの解釈性(Explainable AI: XAI)の基本的な考え方と、なぜそれがビジネスにおいて重要なのかについて解説しました。Part2となる本記事では、具体的なXAIの手法として、Feature ImportancePermutation Importance、そしてSHAPの3つに焦点を当て、それぞれの概念とサンプルコードを交えながら比較解説します。

1. モデル解釈手法の比較

機械学習モデルの解釈性を高めるための手法はいくつか存在しますが、ここでは代表的なFeature Importance、Permutation Importance、SHAPの3つを比較します。

手法名 概要 長所 短所
Feature Importance モデルの構築過程で計算される特徴量の重要度(例:決定木のGini重要度) 実装が容易、計算コストが低い 相関の高い特徴量やカーディナリティの高い連続量を過大評価する可能性がある
Permutation Importance 特定の特徴量の値をシャッフルし、モデルの予測精度の低下を基に重要度を測る モデルに依存しない、相関の高い特徴量や連続量の過大評価が起こりにくい 計算コストが比較的高め、特徴量間の相互作用を考慮しにくい
SHAP (SHapley Additive exPlanations) 協力ゲーム理論に基づき、個々の特徴量が予測に与える貢献度を定量化する 個々の予測に対する詳細な説明が可能、特徴量間の相互作用を考慮できる 計算コストが高い、概念が複雑

2. Feature Importance

Feature Importanceは、主に決定木ベースのモデル(例:Random Forest, LightGBM, XGBoost)において、モデルが構築される過程で計算される特徴量の重要度です。例えば、決定木では、その特徴量を使って分割した際に不純度(Gini不純度やエントロピーなど)がどれだけ減少したかによって重要度が算出されます[1]。

注意点

Feature Importanceは計算が容易である反面、相関の高い特徴量やカーディナリティ(取りうる値の種類)の高い連続量の特徴量を過大評価する傾向があるという問題が指摘されています。これは、モデルがこれらの特徴量を複数回、分割に利用することで、その重要度が高く見積もられてしまうためです。

サンプルコード

ここでは、LightGBMを例にFeature Importanceを計算してみます。

import pandas as pd
import numpy as np
import lightgbm as lgb
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# === 設定: LightGBMの重要度の種類を選択 ===
# 'split'(分割回数) または 'gain'(損失減少量の合計)
IMPORTANCE_TYPE = 'gain'

# Titanicデータの読み込み
df = pd.read_csv('https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv')

# 特徴量の前処理
# 欠損値の処理
df['Age'] = df['Age'].fillna(df['Age'].mean())
df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
df['Embarked'] = df['Embarked'].fillna(df['Embarked'].mode()[0])

# カテゴリカル変数のエンコーディング
dummies = []
cols = ['Pclass', 'Sex', 'Embarked']
for col in cols:
    dummies.append(pd.get_dummies(df[col], prefix=col))

# ダミー変数の結合
titanic_dummies = pd.concat(dummies, axis=1)
df = pd.concat([df, titanic_dummies], axis=1)

# 不要な列の削除
df = df.drop(['PassengerId', 'Name', 'Ticket', 'Cabin', 'Pclass', 'Sex', 'Embarked'], axis=1)

# 特徴量とターゲットの分離
X = df.drop('Survived', axis=1)
y = df['Survived']

# 訓練データとテストデータに分割(1つ目と同じ)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# LightGBMモデルの学習(1つ目と同じ)
lgb_clf = lgb.LGBMClassifier(random_state=42)
lgb_clf.fit(X_train, y_train)

# === LightGBM組み込みのFeature Importanceを取得 ===
# scikit-APIのfeature_importances_は既定で 'split'
# 'gain' を使う場合は booster_ から取得する
if IMPORTANCE_TYPE == 'split':
    importance = lgb_clf.feature_importances_
elif IMPORTANCE_TYPE == 'gain':
    importance = lgb_clf.booster_.feature_importance(importance_type='gain')
else:
    raise ValueError("IMPORTANCE_TYPE must be 'split' or 'gain'.")

# 結果の可視化
feature_importance = pd.DataFrame({
    'feature': X.columns,
    'importance': importance
})

# 重要度でソート(昇順:barhで下ほど重要度大に)
feature_importance = feature_importance.sort_values('importance', ascending=True)

# === プロット(1つ目と同じ体裁に統一) ===
plt.figure(figsize=(10, 8))
plt.barh(feature_importance['feature'], feature_importance['importance'])
plt.xlabel("Importance")
plt.ylabel("Feature")
plt.title("Feature Importance")
plt.tight_layout()
plt.show()

# 数値での確認(降順)
print("\n特徴量重要度のランキング:")
print(feature_importance.sort_values('importance', ascending=False))

出力結果

サンプルコードの出力結果は図1の通りです。注意点でも触れたように、カーディナリティの高い特徴量であるFareとAgeの重要度が高く見積もられています。
image.png
図1 Feature Importanceに基づく特徴量重要度

3. Permutation Importance

Permutation Importanceは、モデルに依存しない(model-agnostic)な手法であり、特定の特徴量の値をシャッフル(パーミュテーション)することで、モデルの予測精度がどのくらい低下するかを評価します。特徴量をシャッフルすることで、その特徴量と目的変数との関係性を断ち切り、モデルの予測への寄与度を測定します。予測精度が大きく低下すればするほど、その特徴量の重要度が高いと判断されます。

注意点

Permutation ImportanceはFeature Importanceの欠点を補う優れた手法ですが、計算コストが比較的高めです。また、シャッフルによって特徴量間の相互作用が失われるため、相互作用が重要なモデルの場合には、その効果を正確に捉えられない可能性があります。

サンプルコード

Permutation Importanceはeli5ライブラリなどを用いて簡単に計算できます。

import pandas as pd
import numpy as np
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
import eli5
from eli5.sklearn import PermutationImportance
import matplotlib.pyplot as plt

# Titanicデータの読み込み
df = pd.read_csv('https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv')

# 特徴量の前処理
# 欠損値の処理
df['Age'] = df['Age'].fillna(df['Age'].mean())
df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
df['Embarked'] = df['Embarked'].fillna(df['Embarked'].mode()[0])

# カテゴリカル変数のエンコーディング
dummies = []
cols = ['Pclass', 'Sex', 'Embarked']
for col in cols:
    dummies.append(pd.get_dummies(df[col], prefix=col))

# ダミー変数の結合
titanic_dummies = pd.concat(dummies, axis=1)
df = pd.concat([df, titanic_dummies], axis=1)

# 不要な列の削除
df = df.drop(['PassengerId', 'Name', 'Ticket', 'Cabin', 'Pclass', 'Sex', 'Embarked'], axis=1)

# 特徴量とターゲットの分離
X = df.drop('Survived', axis=1)
y = df['Survived']

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# LightGBMモデルの学習
lgb_clf = lgb.LGBMClassifier(random_state=42)
lgb_clf.fit(X_train, y_train)

# Permutation Importanceの計算
perm_imp = PermutationImportance(lgb_clf, random_state=42, n_iter=5, scoring='accuracy')
perm_imp.fit(X_test, y_test)

# 結果の可視化
feature_importance = pd.DataFrame({
    'feature': X.columns,
    'importance': np.abs(perm_imp.feature_importances_),
    'std': perm_imp.feature_importances_std_
})

# 重要度でソート
feature_importance = feature_importance.sort_values('importance', ascending=True)

# プロットの作成
plt.figure(figsize=(10, 8))
plt.barh(feature_importance['feature'], feature_importance['importance'])
plt.xlabel("Importance")
plt.ylabel("Feature")
plt.title("Permutation Importance")
plt.tight_layout()
plt.show()

# 数値での確認(降順)
print("\n特徴量重要度のランキング:")
print(feature_importance.sort_values('importance', ascending=False))

サンプルコードの出力結果は図2の通りです。FareとAgeは重要度が上位の特徴量として表れているものの、Feature Importanceほど高く見積もられてはいません。
image.png
図2 Permutaion Importanceに基づく特徴量重要度

4. SHAP (SHapley Additive exPlanations)

Part1でも触れたように、SHAPは協力ゲーム理論に基づき、個々の特徴量が予測に与える貢献度を定量化する強力なXAI手法です[2]。ゲーム理論のシャプレー値(Shapley value)を応用しており、各特徴量が予測にどれだけ「貢献」したかを公平に配分します。これにより、グローバルな(全体的な)特徴量重要度だけでなく、ローカルな(個々の予測に対する)特徴量の寄与も詳細に分析できます。

SHAPの利点と注意点

SHAPの最大の利点は、個々の予測に対する明確な説明が可能である点と、特徴量間の相互作用も考慮できる点です。これにより、「なぜこの顧客がローンを承認されたのか」といった具体的なビジネスケースでの説明が可能になります。

一方で、SHAPは計算コストが高いという欠点があります。特にデータセットのサイズや特徴量の数が多い場合、計算に時間がかかることがあります。また、概念的に他の手法よりも複雑であり、解釈にはある程度の理解が必要です。

サンプルコード

SHAPはshapライブラリを用いて利用できます。

import pandas as pd
import numpy as np
import lightgbm as lgb
from sklearn.model_selection import train_test_split
import shap
import matplotlib.pyplot as plt

# Titanicデータの読み込み
df = pd.read_csv('https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv')

# 特徴量の前処理
# 欠損値の処理
df['Age'] = df['Age'].fillna(df['Age'].mean())
df['Fare'] = df['Fare'].fillna(df['Fare'].mean())
df['Embarked'] = df['Embarked'].fillna(df['Embarked'].mode()[0])

# カテゴリカル変数のエンコーディング
dummies = []
cols = ['Pclass', 'Sex', 'Embarked']
for col in cols:
    dummies.append(pd.get_dummies(df[col], prefix=col))

# ダミー変数の結合
titanic_dummies = pd.concat(dummies, axis=1)
df = pd.concat([df, titanic_dummies], axis=1)

# 不要な列の削除
df = df.drop(['PassengerId', 'Name', 'Ticket', 'Cabin', 'Pclass', 'Sex', 'Embarked'], axis=1)

# 特徴量とターゲットの分離
X = df.drop('Survived', axis=1)
y = df['Survived']

# 訓練データとテストデータに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# LightGBMモデルの学習
lgb_clf = lgb.LGBMClassifier(random_state=42)
lgb_clf.fit(X_train, y_train)

# SHAP Explainerの作成
explainer = shap.TreeExplainer(lgb_clf)

# SHAP値の計算(Explanationオブジェクト)
shap_values = explainer(X_test)

# 結果の可視化
abs_vals = np.abs(shap_values.values)
feature_importance = pd.DataFrame({
    'feature': X.columns,
    'importance': abs_vals.mean(axis=0),
    'std': abs_vals.std(axis=0)
})

# 重要度でソート(昇順:barhで下から上へ重要になる表示は1つ目と同じ)
feature_importance = feature_importance.sort_values('importance', ascending=True)

# プロット(1つ目に揃える:matplotlibでbarh、同じfigsize/軸ラベル/タイトル/tight_layout)
plt.figure(figsize=(10, 8))
plt.barh(feature_importance['feature'], feature_importance['importance'])
plt.xlabel("Importance")
plt.ylabel("Feature")
plt.title("SHAP Feature Importance")
plt.tight_layout()
plt.show()

# 数値での確認(降順)
print("\n特徴量重要度のランキング:")
print(feature_importance.sort_values('importance', ascending=False))

サンプルコードの出力結果は図3の通りです。Permutation Importanceと同様に、FareとAgeは重要度が上位の特徴量として表れているものの、Feature Importanceほど高く見積もられてはいません。
image.png
図3 SHAPに基づく特徴量重要度

5. まとめ

本記事では、機械学習モデルの解釈性向上のための3つの主要な手法、Feature ImportancePermutation Importance、そしてSHAPについて、その概念とサンプルコード、そしてそれぞれの長所・短所を比較しながら解説しました。

  • Feature Importance: 手軽に利用できるが、特定のケースで過大評価のリスクがある。
  • Permutation Importance: モデルに依存せず、Feature Importanceの弱点を補うが、計算コストがやや高い。
  • SHAP: 個々の予測に対する詳細な説明が可能で、特徴量間の相互作用も考慮できる強力な手法だが、計算コストと概念の複雑さが課題。

これらの手法を適切に使い分けることで、モデルの予測根拠をより深く理解し、ビジネスにおける意思決定の信頼性向上やモデル改善に繋げることができます。

参考文献

  • [1]:eli5: A library for debugging machine learning classifiers and explaining their predictions 出典
  • [2]:SHAP: A Unified Approach to Explain the Output of Any Machine Learning Model 出典
8
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?