メインコンテンツへスキップ

Scikit-learn ランダムフォレスト回帰のfeature_importances_の定義

·1236 文字·3 分
目次

はじめに
#

Scikit-learnの回帰木やランダムフォレスト回帰のクラスには、Feature Importances (FI) という説明変数の重要度を示す指標があるが、導出について公式のリファレンスに書かれていなかったため調べた。 結論から述べると、各説明変数による予測誤差の二乗平均の減少量に対して、データ点数の重みを掛けて求めた値である。

記事執筆時点でのバージョンは以下の通り。

ソフトウェア バージョン
Python 3.6.5
Scikit-learn 0.19.1

回帰木のFI
#

ランダムフォレスト回帰は、複数の回帰木の集合であるので、初めに回帰木のFIを確認する。

公式リファンレスには、FIについて以下のように記述されている。

The importance of a feature is computed as the (normalized) total reduction of the criterion brought by that feature. It is also known as the Gini importance. sklearn.tree.DecisionTreeRegressor — scikit-learn 0.24.0 documentation

すなわち、説明変数ごとに、ジニ重要度 (Gini importance) と呼ばれる基準量の減少量を(正規化したものを)合算して得られる、とある。 しかし、ネット上にはGini importanceに関する目ぼしい資料は見つからなかった(ジニ係数やジニ特徴量に関する資料はあるが)。

そこで、自分でプログラムを動かして動作を確認する。

まず、3つの説明変数X0, X1, X2と、目的変数Yを用意し、 DecisionTreeRegressorで学習させる。

import numpy as np
import pandas as pd
from sklearn import tree

X0 = np.array([0,0,1,1]).reshape(-1, 1)
X1 = np.array([0,1,0,0]).reshape(-1, 1)
X2 = np.array([0,0,0,1]).reshape(-1, 1)
X  = np.hstack([X0, X1, X2])
Y  = np.array([1,2,3,4])

t = tree.DecisionTreeRegressor(max_depth=3, random_state=0)
t.fit(X, Y)

回帰木をGraphVizで可視化する。

tree.export_graphviz(t, "tree.dot")

decisiontreeregressor-tree
decisiontreeregressor-tree

図の四角は、回帰木の各ノードを示す。 四角の中の説明は以下の通り。

  • 1行目の不等式が成り立つ場合は、左側のノードに進む。成り立たない場合は、右のノードに進む。
  • mse は平均二乗誤差 (MSE, Mean Squared Error) 。
  • samples はデータ点数。
  • value は予測値。

この中で、mseとsamplesに着目する。 1段目のノードでは、X0 (X[0])によって、4点のデータのMSEが1.25から0.25に減少している。 また、2段目のノードでは、X1 (X[1]), X2 (X[2])によって、それぞれ分岐後の2点のデータのMSEが0.25から0に減少している。

次にFIを表示する。

print(pd.Series(t.feature_importances_, index=["X0", "X1", "X2"]))

実行結果

X0    0.8
X1    0.1
X2    0.1

ここで、X0, X1, X2によるMSEの減少量に対してデータ点数を掛けると、それぞれ、 X0: (1.25 - 0.25)*4 = 4 X1: (0.25 - 0)*2 = 0.5 X2: (0.25 - 0)*2 = 0.5 となる。 減少量の合計が1となるように正規化すると、 X0: 4/(4+0.5+0.5) = 0.8 X1: 0.5/(4+0.5+0.5) = 0.1 X2: 0.5/(4+0.5+0.5) = 0.1 となり、FIと一致している。

すなわち、FIは予測誤差の二乗平均の減少量に対して、データ点数の重みを掛けて正規化した値となる。

ランダムフォレスト回帰のFI
#

ランダムフォレストのFIの計算方法についても、Scikit-learnの公式リファレンスには書かれていない。 しかし、ソースコードを見ると、決定木ごとにFIが計算され、それらの平均がランダムフォレストのFIとなっている(scikit-learnのforest.py 359~375行目、BaseForestクラスより。このクラスは、RandomForestRegressorが継承している)。

    @property
    def feature_importances_(self):
        """Return the feature importances (the higher, the more important the
           feature).

        Returns
        -------
        feature_importances_ : array, shape = [n_features]
        """
        check_is_fitted(self, 'estimators_')

        all_importances = Parallel(n_jobs=self.n_jobs,
                                   backend="threading")(
            delayed(getattr)(tree, 'feature_importances_')
            for tree in self.estimators_)

        return sum(all_importances) / len(self.estimators_)
Helve
著者
Helve
関西在住、電機メーカ勤務のエンジニア。X(旧Twitter)で新着記事を配信中です

関連記事

TensorflowをNehalem以前のPCへの導入する方法
·1052 文字·3 分
Nehalem以前のCPUを持つPCでは、Tensorflowのバージョンを1.5とする。
ChainerのIteratorクラスによる学習用ミニバッチ作成
·2129 文字·5 分
データセットから学習用ミニバッチを作成してくれるIteratorクラスの動作を確認する。
Chainer入門 最小限のニューラルネットワーク実装
·1600 文字·4 分
ディープラーニング用のライブラリChainerの使い方を理解するため、ChainerのChainクラスとOptimizerを使って最小限のニューラルネットワーク (NN) を実装する。
SciPyを使ったFIRフィルタによる波形整形
·1247 文字·3 分
SciPyを使って、FIR (Finite Impulse Response, 有限インパルス応答) フィルタによる離散信号の波形を整形する。ローパス、ハイパス、バンドパス、バンドエリミネイトの各フィルタの設計から、信号への適用まで行う。
NumPyのemptyで空(長さ0)の配列を作る
·1419 文字·3 分
NumPyのempty関数を用いて、空の(要素を持たない)任意の次元の配列を作成できる。本記事では、空の配列の作り方、使い方について簡単に考察する。
NumPyを使った高速フーリエ変換による周波数解析
·1276 文字·3 分
NumPyのfftパッケージを使って、FFT (Fast Fourier Transform, 高速フーリエ変換) による離散信号の周波数解析を行い、信号の振幅を求める。