shapの使い方
概要
- 特徴量の重要度を判別可能
- その方法は特徴量のpermutationを行うことで可能にしている(独立性の確保)
インストール
$ pip install shap
具体例: binary分類
import lightgbm as lgb
import shap
import logging
import warnings
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import pandas as pd
import matplotlib.pyplot as plt
# 警告を抑制
warnings.filterwarnings('ignore', message='No further splits with positive gain, best gain: -inf')
logging.getLogger('lightgbm').setLevel(logging.WARNING)
# データの読み込みとデータフレームの作成
data = load_breast_cancer()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['target'] = data.target
# データの分割
X_train, X_valid, y_train, y_valid = train_test_split(df.drop(columns=['target']), df['target'], test_size=0.2, random_state=42)
# LightGBMのデータセットに変換
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)
# パラメータ設定
params = {
'boosting_type': 'gbdt',
'objective': 'binary',
'metric': ['binary_logloss', 'auc'],
'learning_rate': 0.1,
'num_leaves': 31,
'verbose': -1 # ここで警告を抑制
}
# モデルのトレーニング
gbm = lgb.train(params,
train_data,
num_boost_round=100,
valid_sets=[train_data, valid_data],
valid_names=['train', 'valid'],
callbacks=[lgb.log_evaluation(period=10),
lgb.early_stopping(stopping_rounds=10, first_metric_only=True)])
# SHAP値の計算
explainer = shap.TreeExplainer(gbm)
shap_values = explainer.shap_values(X_valid)
# 特徴重要度のバープロット
shap.summary_plot(shap_values, X_valid, plot_type="bar")
# 特徴の詳細な影響の可視化
shap.summary_plot(shap_values, X_valid)
# 特定のレコードの判断に効いた要素を確認
record_index = 0 # 確認したいレコードのインデックス
shap.force_plot(explainer.expected_value, shap_values[record_index], X_valid.iloc[record_index], matplotlib=True, text_rotation=45)
具体例; JavaScriptで特徴量の可視化を行う
- 各モデルの平均的なshapの値を計算し、平均を計算する
shap.initjs()
でJSを初期化- プロットを行う
平均値の計算
import shap
shap_vals = []
for model in ret["models"]:
explainer = shap.TreeExplainer(model)
shap_val = np.array(explainer.shap_values(X))
shap_vals.append(shap_val)
shap_val_np: np.array = np.mean(shap_vals, axis=0)
サマリーの計算
shap.initjs()
shap.summary_plot(shap_val_np[1, :], X)
具体例; CVで学習し、回帰で使用する例
- shapは一度に1つのモデルしか評価できないので、複数のモデルを利用する際は、すべてのモデルをshapで調査し、結果の平均を計算する
shap実行部分
import shap
shap_vals = []
for model in ret["models"]:
explainer = shap.TreeExplainer(model)
shap_val = np.array(explainer.shap_values(X_train))
shap_vals.append(shap_val)
shap_val = np.mean(shap_vals, axis=0)
# shap_val = shap_val[1, :] # 回帰の場合、必要ない
shap_val= pd.DataFrame(shap_val)
shap_val.columns = [f"{c}_sv" for c in X_train.columns]
shap = pd.concat([X_train, shap_val], axis=1)
display(shap)
特徴量がポジティブ、ネガティブに働くかを計算
data = []
for fname in ["feat_0", "feat_1", ...]:
x = shap.copy()
x[f"{fname}_sv"] = (x[f"{fname}_sv"] > 0).astype(int)
data.append( (fname, x[f"{fname}_sv"].mean() ) )
x = pd.DataFrame(data)
x.columns = ["特徴量名", "ポジティブに働く確率"]
x.sort_values(by=["ポジティブに働く確率"], ascending=False, inplace=True)
display(x)