shapの使い方
概要
- 特徴量の重要度を判別可能
- その方法は特徴量のpermutationを行うことで可能にしている(独立性の確保)
インストール
$ python3 -m pip install shap
具体例: binary分類
学習部分
import lightgbm as lgb
from sklearn.metrics import roc_auc_score
param = {
"objective": "binary",
"metric": "auc",
"max_depth": 4,
"num_leaves": 4,
"learning_rate": 0.1,
"bagging_fraction": 1.,
"feature_fraction": 1.,
"lambda_l1": 0.,
"lambda_l2": 0.5,
"bagging_seed": 777,
"verbosity": -1,
"seed": 777,
}
X = train.drop(["label"], axis=1)
Xval = val.drop(["label"], axis=1)
y = train["label"]
yval = val["label"]
cats_index = []
def shot_train(X, y, Xval, yval, cats_index, param, eval_func, verbose, early_stopping_rounds, n_estimators):
trn_data = lgb.Dataset(X, label=y, categorical_feature=cats_index)
val_data = lgb.Dataset(Xval, label=yval, categorical_feature=cats_index)
num_round = n_estimators
clf = lgb.train(param, trn_data, num_round, valid_sets=[
trn_data, val_data], verbose_eval=verbose, early_stopping_rounds=early_stopping_rounds)
test_predictions = clf.predict(Xval)
eval_loss = eval_func(yval, clf.predict(Xval))
print(f'end eval_loss={eval_loss}')
return clf, X, y
shap実行部分
import shap
clf, X, y = shot_train(X, y, Xval, yval, cats_index, param, roc_auc_score, 1, 50, 100000)
explainer = shap.TreeExplainer(clf)
shap_val = np.array(explainer.shap_values(X))
shap_val = shap_val[1, :] # multi-classの場合、ここの親の次元がクラス数ぶん増える
shap_val= pd.DataFrame(shap_val)
shap_val.columns = [f"{c}_sv" for c in X.columns]
df = pd.concat([X, shap_val], axis=1)
display(df)
for fname in ["可視化したい特徴量名"]:
tmp = df.groupby(by=[fname]).agg(mean_feat = (f"{fname}_sv", "mean")).reset_index()
ax = sns.scatterplot(x=tmp[fname], y=tmp["mean_feat"])
具体例; 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)