【機械学習】Permutation Importanceでモデルの変数重要度を解釈する

こんにちは。今回は、機械学習モデルの変数重要度を計測する手法の一つである、Permutation Importanceについて調べてみたことをまとめておきたいと思います。

Permutation Importanceとは?

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

つまり、Permutation Importanceは、ある特徴量の値を、データレコード間で完全にランダムにシャッフルして予測を行ったときに、どの程度予測精度が低下するかによって重要度を判断する方法になります。

もしその特徴量がモデルの予測精度向上に大きく寄与していたのであれば、シャッフルしてしまうことで大きく精度が下がる(=重要度が高かった)。一方で、精度向上に寄与しない変数であれば、シャッフルしても精度は変わらないだろう(=重要度が低かった)、という考え方です。

とても直感的ですね。絵にするとこんなイメージかと思います。

Permutation Importanceのイメージ

Permutation Importanceの登場

Permutationという考え方は、2001年にランダムフォレストが発表された際に登場しているようです。

https://link.springer.com/content/pdf/10.1023/A:1010933404324.pdf

この点はScikit-Learnの公式ドキュメントでも上の論文が引用される形で言及されています。

https://scikit-learn.org/stable/modules/permutation_importance.html

The permutation feature importance is defined to be the decrease in a model score when a single feature value is randomly shuffled

Scikit-Learnの公式ドキュメントより

Permutation Importanceの特徴

上記のような計測方法であることで、Permutation Importanceには以下の特徴があります。

機械学習モデルの種類に依存しない

Permutation Importance計測の過程では、モデルの種類を意識しません。単純にデータをシャッフルして、結果として出力される予測値がどう変化するかを計測するだけです。

なので、どんなモデルに対しても計測することができます。

他の信頼できる重要度算出手法と比べて計算コストが低い

Permutation Importanceの考え方を理解すると、「あれ?そもそもその特徴量をシャッフルなんかせず、特徴量自体を削って精度がどれだけおちるか計測した方が良いんじゃね?」とも思えます。

ただ、これを実現しようとすると、モデルの学習工程も特徴量の数だけ繰り返していく必要があって計算コストが高くなります。

Permutation Importanceでは、学習モデルはそのままに、検証データだけ*シャッフルして予測を繰り返すので、計算コスト低く重要度が算出できます。

*Permutation Importance計測に利用するデータ

Permutation Importanceの計測に使用するデータは、上では検証データと書きましたが、実は学習(訓練)データを利用する方法もあります。

この点はScikit-Learnの公式ドキュメントにも説明があり、以下の点が言及されています。

  • 検証データを利用して計測することで、モデルの汎化性能(Generalization Powerと書いているけど、解釈あってるかな・・)への寄与度が最も高い特徴量を知ることができる
  • 学習(訓練)データで計測すると、モデルがどの特徴量を重視して学習されたかが分かる。
  • これらを比較して、例えば学習データで計測したPermutation Importanceでは重要度が高いが、検証データで計測すると重要度が低い、といったギャップがあれば、過学習を疑うことができる

参考:

https://scikit-learn.org/stable/modules/permutation_importance.html

Permutation Importanceの数学

Permutation Importanceは、数式だと以下のように表現されます。

Scikit-Learnの公式ページより

ここで、各文字・変数は以下を表しています。

  • i : 変数重要度
  • j:特徴量
  • s:もともとの予測スコア
  • K:データレコード(Importance算出に利用する検証データまたは学習データ)の数
  • k:k番目のデータレコード
  • s k,j:特徴量jをシャッフルしたときのデータkの予測スコア

つまり、ある特徴量jの重要度iは、本来の予測スコアから、jをシャッフルした時の予測スコアをデータセット分算出して平均をとったもの、として表現されることになります。

参考:

https://scikit-learn.org/stable/modules/permutation_importance.html#outline-of-the-permutation-importance-algorithm

決定木モデルにおけるGini Importance vs Permutation Importance

この点が、今回私がPermutation Importanceを使いたいと思った動機です。

決定木系のモデルの変数重要度には、Gini Importanceも有名かと思います。これは、Scikit-LearnのRandom Forestモデルの変数重要度測定の規定値となっています。

https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html#sklearn.ensemble.RandomForestClassifier.feature_importances_

このGini ImportanceとPermutation Importanceはどう使い分ければよいのでしょうか?

まず、Gini Importanceには1つ問題点があります。変数のカーディナリティ(取りうる値の種類)の違いによって重要度のバイアスが発生し得ます。

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

なので、予測精度よりも説明性・解釈することを重視するようなモデル構築においては、こうしたバイアスが含まれていると誤った解釈をしてしまう可能性があるため、Permutation Importanceに注目した方が良いように思えます。

この点について、Scikit-Learnの公式ドキュメントにも見解が記載されています。Permutation ImportanceはGini Importanceの制約を克服した手法、というように書かれているので、なんとなくPermutation Importance推しのようにも読み取れます。

Warning : Impurity-based feature importances can be misleading for high cardinality features (many unique values). See Permutation feature importance as an alternative below.

…..

Permutation feature importance overcomes limitations of the impurity-based feature importance: they do not have a bias toward high-cardinality features and can be computed on a left-out test set.

https://scikit-learn.org/stable/auto_examples/ensemble/plot_forest_importances.html#feature-importance-based-on-mean-decrease-in-impurity

じゃあなんでRandom Forestの規定値はGini Importanceなんでしょうね・・?

以下のブログの最後にもヒントとなりそうなことが書かれていましたが、上記バイアスの発生し得ない状況(=特徴量間のカーディナリティが均等)においては、最も計算コスト低く(=Permutation Importanceを計測するための追加の予測を行う必要がない)妥当な解釈を与えることができるため、なのかもしれませんね。

https://blog.methodsconsultants.com/posts/be-aware-of-bias-in-rf-variable-importance-metrics/

ただ、現実世界のデータを使ってモデルを作っていくとき、よっぽど特徴量加工を精密にやらない限りそんな状況ってそうそうありえるのかなぁという気もしたので、そこまで計算コストが問題にならないのであればPermutation Importanceで計測しておいたらいいんじゃないか、という気がしました。(どなたか知見のある方いらっしゃれば是非教えてくださいm(_ _)m)

なお、たまたま見つけた「The revival of the Gini importance?」という2018年の論文があるのですが、こちらを見ると、そもそもGini Importanceのバイアスを発生しなくするような研究も行われているようでした。今後また、このあたりの常識も変わってくるかもしれませんね。

https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6198850/

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を可視化することができました!

ご参考になりましたら幸いです!最後に、この記事に関するフィードバックがありましたら、以下の「いいね」ボタンや、コメントを残していただけると幸いです!今後の記事改善に役立てていきたいと思います。

モデルの解釈をもっと勉強するなら・・

最近読んだこちらの本が、今回解説したPermutation Importanceを含め、機械学習モデルのふるまいを解釈する方法を体系的にまとめてくれていて大変参考になりました!

おしまい

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

コメントを残す

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

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