permutation importance 〜特徴量の重要度の測り方〜

概要

Random Forestや勾配ブースティングなどの決定木アルゴリズムのアンサンブル手法の強みは性能の高さの他に入力に用いた各特徴量の重要度を算出できることにあります。各特徴量の重要度の大きさを元に特徴量選択を見直し、モデルの性能の向上を図ることもデータサイエンスでは一般的です。 決定木アルゴリズムのアンサンブル手法では不純度(デフォルトではジニ不純度)に基づいて木を分割しています。scikit-learn, xgboost, lightGBMなどのライブラリで feature_importances_メソッドで算出する特徴量の重要度は学習時に使用した不純度に基づいたものです。この重要度は gini importancemean decrease impurityと呼ばれます。しかし、算出した各特徴量の重要度の値の比は性能にどれだけ貢献しているかとは一般的には関連がありません。そこで本記事でとりあげるのがpermutaion importanceです。

permutation importance

permutation importanceはジニ不純度などの分割手法にも依存しない非常にシンプルな特徴量の算出手法です。

  • 簡単のためRandom Forestに入力するデータとして特徴Aと特徴Bの2つの特徴を持つデータを考える。
  • まず、データをtrainデータとvalidation dataに分ける。trainデータの特徴A,Bを学習させ、モデルを訓練する。
  • 訓練後validation dataを使用してモデルの性能をタスクに適切な評価手法で測定する(分類タスクであればaccuracy, 回帰タスクであればR2 scoreなど)。この時の性能値をbaselineとする。
  • 続いてtrainデータの特徴Aの値をランダムにシャッフルしてから訓練し、その性能をvalidationデータで測定する。
  • 同様に特徴Bの値をtrainデータの特徴Bの値をランダムにシャッフルしてから訓練し、その性能をvalidationデータで測定する。
  • 各特徴をランダムにシャッフルした時にbaselineに比べて性能がどの程度落ちたかを計算することで各特徴がどのくらい性能に貢献しているかを正確に算出する。

f:id:internetz:20181209220521p:plain

ポイントは特徴量をランダムにシャッフルすることで、特徴のデータ分布を変化させずに特徴の性能への貢献をゼロにしているところです。

使いどころ

permutaion imporanceを用いて各特徴の性能への寄与を正確に算出することができることがわかりましたが、ではその使いどころはどこでしょうか。ここでは一つユースケースを提案したいと思います。例えば、random forestで訓練した回帰予測モデルがある実システムで毎分1回推論し、その予測値とそのモデルの予測性能をシステムが使用しているとします。推論時にはその1分前にシステム内で生成されたログデータを特徴として入力に用いているとします。しかし、システムの仕様上ログデータの一部が欠損することもあり、入力すべき特徴が揃わないことがあります。この時に各特徴が欠損した場合どの程度予測性能が落ちるのかpermutation importanceで分かっていれば、特徴の欠損による性能の変化を考慮したシステム運用ができます。

実装

実際にrandom forestでpermutation importanceを算出してみます。上で説明した通り、permutation importanceのアルゴリズムは非常にシンプルであるため実装を簡単ですが、random forestでpermutation importanceを算出できるpythonライブラリがあるので今回はそのライブラリを使用してみます。

github.com

ライブラリのインストール

pip install rfpimp

簡単のためscikit-learnにプリセットされているデータセットであるBoston house-prices(ボストン市の住宅価格)の全てのカラムをそのまま(特徴設計せず)入力データとして使用し、Random Forestを用いた住宅価格の回帰予測モデルを構築した後permutaion importanceにより、各特徴(=データセットのカラム)が性能にどの程度貢献しているか算出し、可視化します。 ソースコードは以下。

import pandas as pd
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from rfpimp import *


#データセットを読み込み、入力データと目的変数のデータを9:1比でtrainデータとvalidationに分割
boston = load_boston()
x_data = pd.DataFrame(boston.data, columns=boston.feature_names)
y_data = boston.target
x_train, x_val, y_train, y_val = train_test_split(x_data, y_data, test_size=0.10)

# trainデータを用いてRandom Forestを訓練
forest = RandomForestRegressor()
forest.fit(x_train, y_train)

# validationデータを用いてR2-scoreによるpermutaion importanceを算出及び可視化
imp = importances(forest, x_val, y_val)
vizualization = plot_importances(imp)
vizualization.view()

以下の図が得られました。 f:id:internetz:20181209220529p:plain