機械学習界隈で、最強アルゴリズムの一角を占めていたランダムフォレスト。ディープラーニングが登場した後急速に存在感をなくすものの、その利便性と強力さから多くのデータサイエンティストが現役利用中。

scikit-learnでのランダムフォレスト、分類モデルと重要度評価の実装方法まとめました。

決定木の問題点

決定木は、上から順に条件分岐を作って分類モデルを作る手法です。ルールが可視化できる、正規化や標準化などのデータ加工が不要など、素晴らしいアルゴリズムです。
しかし、決定木は過学習を起こしやすいという問題点がありました。

参考記事:人工知能できのこ派とたけのこ派を予測する【python決定木】

ランダムフォレストとは

ランダムフォレストは、決定木をたくさん作ってその結果を多数決(平均化)することで、決定木の過学習を平準化するアルゴリズムです(アンサンブル学習と言います)。

ランダムフォレストの学習手順は、
1.ランダムにデータを選択する(サンプル数と特徴量を複数組分選択する)
2.複数の決定木を作る
3.複数の決定木の結果を多数決して分類結果を決定する。

という流れになります。

そしてランダムフォレストの特徴は4つあります。
1.多数決によるアンサンブル学習のため過学習が起こりにくい
2.特徴量の標準化や正規化の処理が必要ない
3.ハイパーパラメータが少ない(サンプリング数と決定木の特徴量数くらい)
4.どの特徴量が重要かを知ることができる

特に4番が最強です。

RandomForestClassifierとExtraTreesClassifierの違い

scikit-learnでランダムフォレストの分類モデルには、RandomForestClassifierとExtraTreesClassifierがあります。
scikit-learnのチュートリアルを見る限り、使い分けとしては、精度の高い分類モデルを作りたい場合はRandomForestClassifierを利用し、特徴量の重要度を特に評価したい場合はExtraTreesClassifierを利用することが多いようです。今回は、RandomForestClassifierを利用します。

なお、ランダムフォレストで回帰を行う場合は、RandomForestRegressorやExtraTreesRegressorのクラスを活用してください。

RandomForestClassifierの主なパラメータ

ランダムフォレストもハイパーパラメータの設定が必要です。ただランダムフォレストの場合、ほぼデフォルトでもいい精度が出るのであまりこだわらなくても大丈夫です。こだわる人は、いろいろ設定してグリッドサーチしましょう。

・n_estimators →デフォルト値10。決定木の数。
・max_features →デフォルト値は特徴量数の平方根。決定木の特徴量の数。大きいと似たような決定木が増える、小さいと決定木がばらけるがデータに適合できにくくなる。
・random_state →デフォルト値なし。乱数ジェネレータをどの数値から始めるか。前回と異なるモデルを得たい場合は数値を変更すると良いです。
max_depth →デフォルト値なし。決定木の最大の深さ。
min_samples_split →デフォルト値2。木を分割する際のサンプル数の最小数。

ランダムフォレストの分類モデル実装

scikit-learnのランダムフォレストで、分類モデルを実装します。データはおなじみのIrisデータです。言語はpython2.7です。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.ensemble import RandomForestClassifier
import sklearn.cross_validation as crv
from sklearn.metrics import accuracy_score
from sklearn.datasets import load_iris

# Pandas のデータフレームとして表示
iris = load_iris()
df = pd.DataFrame(iris.data, columns=iris.feature_names)

#データの定義
x = iris.data
y = iris.target

#学習データとテストデータに分割
x_train, x_test, y_train, y_test = crv.train_test_split(x, y, test_size=0.20, random_state=42)

# 学習
clf = RandomForestClassifier(n_estimators=20, random_state=42)
clf.fit(x_train, y_train)

#予測データ作成
y_predict = clf.predict(x_train)

#正解率
print accuracy_score(y_train, y_predict) 

→ホールドアウト法で評価したところ正解率100%でした。
 本当はクロスバリデーションでの評価が必要です。評価方法は以下をお読みください。

参考記事:交差検定(クロスバリデーション)など機械学習の評価方法まとめ

特徴量の重要度を評価する方法

scikit-learnのランダムフォレストでは、特徴量の重要度を算出できます。重要度の算出方法は、以下の通りです。

1.ランダムにデータを取って決定木を作る。
2.作った決定木のある特徴量について、データの並び順をぐちゃぐちゃにする。
3.ぐちゃぐちゃにする前と後で、決定木の精度が変わるかどうか比較する。
4.精度が大きく変わったら重要な特徴量、変わらなかったら重要でない特徴量とする。
5.いろんな決定木で1~4を繰り返して、多数決する。

重要度は、あくまで特徴量全体から見た相対的な指標です。そのため、すべての特徴量の重要度を足すと1になります。数字自体が意味を持つ相関とは、また違った概念です。

ちなみに重要度評価は、実務でもかなり使えます。ディープラーニングで学習させる前に、ランダムフォレストで特徴選定するとか結構聞きますね。

ランダムフォレストで特徴量の重要度評価を実装

feature_importances_関数で特徴量の重要度を取得できます。今回コードでは、重要な特徴量を上から並べ棒グラフを作りました。

#特徴量の重要度
feature = clf.feature_importances_

#特徴量の重要度を上から順に出力する
f = pd.DataFrame({'number': range(0, len(feature)),
             'feature': feature[:]})
f2 = f.sort_values('feature',ascending=False)
f3 = f2.ix[:, 'number']

#特徴量の名前
label = df.columns[0:]

#特徴量の重要度順(降順)
indices = np.argsort(feature)[::-1]

for i in range(len(feature)):
    print str(i + 1) + "   " + str(label[indices[i]]) + "   " + str(feature[indices[i]])

plt.title('Feature Importance')
plt.bar(range(len(feature)),feature[indices], color='lightblue', align='center')
plt.xticks(range(len(feature)), label[indices], rotation=90)
plt.xlim([-1, len(feature)])
plt.tight_layout()
plt.show()

→出力結果
1   petal length (cm)   0.440336982824
2   petal width (cm)   0.415328928276
3   sepal length (cm)   0.11628156486
4   sepal width (cm)   0.0280525240407

petal length (cm) が最も重要な特徴量と評価されました。
100

学習データの項目がたくさんある場合、全てのデータを学習に使うのではなく、ランダムフォレストで特徴量を評価して、重要でない特徴量を削除すると精度が上がることがとても多いです。

人工知能ビジネスが急激に盛り上がっている現在、ディープラーニングのようなキラキラ系技術ではなく、ランダムフォレストのような堅牢で枯れた技術を使うことが、最初の一手としてふさわしいと強く感じます。

参考図書:



機械学習を勉強したい方:AIエンジニアが教えるゼロから機械学習の勉強法