Permutation Importanceでモデル重要変数を計測する

こんにちは。今回は、ツリー系機械学習モデルの変数重要度を計測する手法の一つである、Permutation Importanceの活用方法をご紹介いたします。

なぜGini ImportanceよりPermutation Importance?

ツリー系機械学習モデルの変数重要度には、一般的に以下の計測方法があります。

  • Gini Importance
  • Split Importance
  • Permutation Importance
  • SHAP Importance など

現在一般的に広く使われているものは、Gini Importanceだと思われますが、これは、ざっくり言うと「その特徴量は、目的指標を綺麗に分類するためのツリーの枝の分岐にどれだけ貢献したか」を表しています。

詳細の数学は、また別の記事で整理しようと思いますが、この方法には一つ落とし穴があります。それは、変数のカーディナリティ(取りうる値の種類)の違いによるバイアスが発生しうる点です。

これについては、こちらの記事に分かりやすく書かれていましたのでリンクを貼らせていただきます。

さて、単純に予測精度を追求したモデルを構築する場合には、ご参考としてGini Importanceを見る、でも良いかもしれませんが、予測精度よりも説明性・解釈することを重視するようなモデル構築においては、このバイアスは致命的になりかねません。「この変数が一番重要度が高い!なのでこれに対してビジネスの対策を考えよう」といった場合に、実はその変数の重要度が他の変数より高かったのは、他変数より変数のカーディナリティが高かったから、というオチだったらなんだかお粗末です・・

前置きが長くなりましたが、そんなときに有効なのが、今回ご紹介するPermutation Importanceです。

Permutation Importance計測の仕組み

Permutationとは、日本語に訳すると「置換」「並び替え」になります。

そうです。Permutation Importanceの計測方法は、とても直感的で、Importanceを計測したいある変数を、データセットの中でランダムに入れ替えを行い(ランダマイズ)、予測を行ったときに、どの程度予測精度が低下するかを計測します。

このとき、その変数がモデルの精度に対して重要であれば、ランダマイズすることで大きく精度が下がるはずです。一方で、重要でない変数であれば、ランダマイズしても精度は変わらないでしょう。

このような計測方法を取ることで、Gini Importanceで発生しうるバイアスを取り除いて重要度を計測することができます。

Permutation Importanceの実装

それでは、最後にPermutation Importanceを実際に実装してみたいと思います。

これ、Scikit-LearnのVersion 0.22からScikit-Learn上にメソッドが標準装備されています。便利!

以下の宣言で利用できるようになります。

from sklearn.inspection import permutation_importance

今回はボストンの住宅価格データセットを使って実験してみます。Importanceの実装が目的なので特徴量エンジニアリングの過程は端折ります。

## 今回の実験で利用しないメソッドもImportしたりしてますが、無視してください
from sklearn.datasets import load_boston
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import RandomForestRegressor
from sklearn.inspection import permutation_importance
from sklearn.model_selection import KFold, StratifiedKFold, GridSearchCV, train_test_split,cross_val_score
from sklearn.metrics import mean_squared_error, roc_auc_score, r2_score

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()

## データセットのロード
#######################################################
boston = load_boston()

data_X = pd.DataFrame(boston.data, columns=boston.feature_names)
data_y = boston.target

data_X.head()

## ランダムフォレストで予測モデルの構築
#######################################################
from sklearn.ensemble import RandomForestRegressor

X_train, X_test, y_train, y_test = train_test_split(data_X, data_y, test_size=0.2, random_state=440)

clf = RandomForestRegressor(n_estimators=30,max_depth=9)
#print("Cross Val Score (MSE):"+str(cross_val_score(clf, data_X, data_y, cv=5, scoring='r').mean()))

clf = clf.fit(X_train, y_train)
pred = clf.predict(X_test)

print(mean_squared_error(y_test, pred))

## Gini Importanceの可視化
df_importance = pd.DataFrame(zip(X_train.columns, clf.feature_importances_),columns=["Features","Importance"])
df_importance = df_importance.sort_values("Importance",ascending=False)

plt.figure(figsize=(10,5))
sns.barplot(x="Importance", y="Features",data=df_importance,ci=None)
plt.title("Gini Importance")
plt.tight_layout()
Gini Importance

まずは、標準で計測されるGini Importanceを可視化してみました。続けてPermutation Importanceです。

以下の構文で計算することができます。可視化に映る前に、戻り値のデータセットの中身をみてみます。

result = permutation_importance(clf, X_test, y_test, n_repeats=5, random_state=42)
result

各特徴量、n_repeatsで指定したfoldの分だけImportanceが計測されて値が入っています。なので、可視化する場合は、平均値などを取って可視化してやれば良さそうです。

それでは、最後に可視化してみます。

df_importance = pd.DataFrame(zip(X_train.columns, result["importances"].mean(axis=1)),columns=["Features","Importance"])
df_importance = df_importance.sort_values("Importance",ascending=False)

plt.figure(figsize=(10,5))
sns.barplot(x="Importance", y="Features",data=df_importance,ci=None)
plt.title("Permutation Importance")
plt.tight_layout()

すみません、ボストンのデータセットはあまり使ったことがなくて内容ちゃんと把握していないのでこの場で結果の比較考察は行いませんが、以上でPermutation Importanceを可視化することができました!

ご参考になりましたら幸いです!

おしまい

0

この記事を気に入っていただけたらシェアをお願いします!

コメントを残す

メールアドレスが公開されることはありません。

ABOUT US

アバター
Yuu113
初めまして。Yuu113と申します。 兵庫県出身、東京でシステムエンジニアをしております。現在は主にデータ分析、機械学習を活用してビジネスモデリングに取り組んでいます。日々学んだことや経験したことを整理していきたいと思い、ブログを始めました。旅行、カメラ、IT技術、江戸文化が大好きですので、これらについても記事にしていきたいと思っています。