【ランダムフォレスト】ブートストラップ法を決定木に応用|python
今回は、決定木に対するバギングの拡張系アルゴリズムである「ランダムフォレスト(random forest)」を解説いたします。
アンサンブル手法のひとつである、バギングについても解説します。
決定木について復習したい方は、【機械学習】決定木の仕組みと実装方法について|pythonをご覧ください。
ランダムフォレスト(random forest)
バギング(bagging)
ランダムフォレストの前に、まずはバギングを学習しましょう。
バギングとは、アンサンブル手法の一つで以下のような特徴があります。
・データセットを複数使って予測を行う。
・元のトレーニングデータに外れ値が混じっていても、影響を受けにくい。
・ブートストラップ法を予測の安定化に使う
ブートストラップ法については、【少ないデータを多く見せる】ブートストラップ法について(パラメトリック編)で概念を中心に解説いたしました。
ブートストラップ法は、データのリサンプリング(復元抽出)を使って推定量の信頼区間を構成したり、バイアスの補正を行うための統計的な手法です。
①まずはあるデータセットDからB個のデータセットを作ります。
データセットDのうち、(xi,yi)を確率1/nでn個復元抽出 →データセットD1とする。 これをB回繰り返し、D1,D2,‥,DBというデータセットを作ります。
②リサンプリングデータをすべて用いて学習を行い、予測のための関数を作る。
-分類問題-
一つ目が予測のための関数。
二つ目が予測のための関数を統合した関数です。
$$\psi D_{b}(X_{i})(b=1,..,B),(\hat{y})=argmax | (b:\psi D_{b}(x)=y)$$
argmax:ある集合の中で関数が最大になるxの集合を返します。
要するにデータセットごとに予測値を出し、1が多いか、0が多いか多数決をしているだけです。
-回帰問題の場合-
$$(\hat{y})={\frac{1}{B}}(\sum_{b=1}^{B}\psi D_{b}(x_{i}))$$
こちらの方がわかりやすいですね。平均を取っているだけです。
基本的に単独の決定木よりもバギングした方が、予測精度が上がる傾向にあります。
色々なモデルを合わせたブレンディング(blending)とは異なります。
あくまでモデルはひとつ。データセットを複数回使い回すことが、バギングです。
ランダムフォレストの仕組み
さて、冒頭でもお伝えしましたが、ランダムフォレストとは決定木に対するバギングの拡張版です。
-何が拡張なのか-
バギングは、データセットをランダムに復元抽出し、予測値を平均するという仕組みです。
それに加えてランダムフォレストは、特徴量までもランダムに選択します。
→これにより、それぞれ多様な決定木を作成することができ、外れ値などに頑健なモデルを作ることができます。
また、決定木単体よりも過学習を起こしにくいという特徴もあります。
あるノードの分岐\(Xk > c\)であるとき、kは以下のように選択されます。
特徴量の総数d個だとすると、\(O√d\)程度の要素を選択し、その中からkを選択する。
このように、各ノードの分岐条件に現れる特徴量をランダムに制約することで、決定木自体に多様性を持たせることができます。
この「多様性」をもう少し詳しく解説します。
強力な予測力のある特徴量があると、予測力がそれほどない特徴量はノードの分割には使われにくいです。
ある決定木の作成に使われない特徴量があると、予測力がない特徴量も分割に使われる機会が増えるよ、ということです。
実務ベースで言うと、単なるブートストラップ法よりもランダムフォレストの方が計算スピードが速いです。
これは、当然ですが決定木dの作成に使われない特徴量があるためです。
*ここでいう予測力がある特徴量と言うのは、ノードを分ける基準に使うと大きく不純度が減る/情報利得が大きいと言う特徴量であり、目的変数への貢献度合いが大きいと言う意味ではありませんのでご注意ください。
【XGB】GridSearchを使いつつ特徴量重要度を知りたいッ‥!|python
バギングとスタッキングはどう違うのか?
スタッキングは、複数の基本モデル(base models)を組み合わせ、それらの予測結果を入力としてメタモデル(meta model)が新たな予測を行うアンサンブル学習手法です。スタッキングの仕組みは以下のようになります。
スタッキングは、結局いろんなモデルの線型結合として表すことができます。
$$f(x;a)={\sum_{k}a(β^k)}×f_{base}(x;β^k)$$
1:トレーニングデータをK分割し、K-1分割のデータで基本モデルを学習させます。
2:学習済みの基本モデルを使って、残り1分割のデータに対する予測を行います。
3:すべての分割について上記の手順を繰り返し、新たな特徴量として予測結果をまとめます。
4:新たな特徴量を用いてメタモデルを学習させ、最終的な予測を行います。
【SHAP】スタッキング(stacking)で特徴量の解釈はできるのか|pythonアンサンブル学習
CODE
今回も実装は乳がんデータを使います。
まずは必要なライブラリをインポートして、データの確認をします。
from sklearn.datasets import load_breast_cancer
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.ensemble import RandomForestClassifier
data_breast_cancer = load_breast_cancer()
# Pandasによるデータの表示
df_target = pd.DataFrame(data_breast_cancer["target"], columns=["target"])
df_data = pd.DataFrame(data_breast_cancer["data"], columns=data_breast_cancer["feature_names"])
df = pd.concat([df_target, df_data], axis=1)
df.head()
target | mean radius | mean texture | mean perimeter | mean area | mean smoothness | mean compactness | mean concavity | mean concave points | mean symmetry | … | worst radius | worst texture | worst perimeter | worst area | worst smoothness | worst compactness | worst concavity | worst concave points | worst symmetry | worst fractal dimension |
1.000000 | -0.730029 | -0.415185 | -0.742636 | -0.708984 | -0.358560 | -0.596534 | -0.696360 | -0.776614 | -0.330499 | … | -0.776454 | -0.456903 | -0.782914 | -0.733825 | -0.421465 | -0.590998 | -0.659610 | -0.793566 | -0.416294 | -0.323872 |
-0.730029 | 1.000000 | 0.323782 | 0.997855 | 0.987357 | 0.170581 | 0.506124 | 0.676764 | 0.822529 | 0.147741 | … | 0.969539 | 0.297008 | 0.965137 | 0.941082 | 0.119616 | 0.413463 | 0.526911 | 0.744214 | 0.163953 | 0.007066 |
-0.415185 | 0.323782 | 1.000000 | 0.329533 | 0.321086 | -0.023389 | 0.236702 | 0.302418 | 0.293464 | 0.071401 | … | 0.352573 | 0.912045 | 0.358040 | 0.343546 | 0.077503 | 0.277830 | 0.301025 | 0.295316 | 0.105008 | 0.119205 |
-0.742636 | 0.997855 | 0.329533 | 1.000000 | 0.986507 | 0.207278 | 0.556936 | 0.716136 | 0.850977 | 0.183027 | … | 0.969476 | 0.303038 | 0.970387 | 0.941550 | 0.150549 | 0.455774 | 0.563879 | 0.771241 | 0.189115 | 0.051019 |
-0.708984 | 0.987357 | 0.321086 | 0.986507 | 1.000000 | 0.177028 | 0.498502 | 0.685983 | 0.823269 | 0.151293 | … | 0.962746 | 0.287489 | 0.959120 | 0.959213 | 0.123523 | 0.390410 | 0.512606 | 0.722017 | 0.143570 | 0.003738 |
y = df["target"]
X = df.loc[:, "mean radius":]
yとXに代入します。yには目的変数、Xには説明変数です。
# 訓練データとテストデータに分ける
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.5, random_state=0)
訓練データとテストデータに分けます。
train、valid、testの区別はちゃんとしておきましょう。
train:教師データ
valid:モデルの評価用データ
test:実際に予測値を出すときに使うデータ
param_grid = {'max_depth': [3,4,5,6,7,8],
'min_samples_leaf': [1,2,3,4,5]}
rfc_gs = GridSearchCV(RandomForestClassifier(n_estimators=100, n_jobs=-1, random_state=42), param_grid, cv=10)
rfc_gs.fit(X_train, y_train)
print('Best Parameters: {}'.format(rfc_gs.best_params_))
print('CV Score: {}'.format(round(rfc_gs.best_score_, 3)))
今回はグリッドサーチ(grid search)を使って、ランダムフォレストのパラメータをチューニングします。
グリッドサーチに関する詳しい説明は、【XGB】交差検証法を使った勾配ブースティング決定木の実装|pythonにあります。
param_gridという辞書型の変数に、パラメータと探索候補を格納します。
ちょっと時間がかかると思います。
rfc_gs.fit(X_train,y_train)で学習してモデルを作ります。
次に評価データを入れてみましょう。
print(rfc_gs.score(X_train, y_train), 3)
print(rfc_gs.score(X_valid, y_valid), 3)
→0.9929577464788732 3
0.9368421052631579 3
最後に評価データを元に予測値を出力させます。
opt_model = rfc_gs.best_estimator_
pred = opt_model.predict(X_valid)
print(pred)
→array([0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0,
1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1,
0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1,
0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1,
1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 1,
1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0,
1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1])
さて、アンサンブル手法にはバギングの他にも単純なブレンディングやブースティング、スタッキングなどがあります。
勾配ブースティング決定木については、以下をご覧ください。
【XGB】交差検証法を使った勾配ブースティング決定木の実装|python
基本精度は上がるしアンサンブル法はやった方が良いとは考えられますが、モデルが複雑になり、解釈が難しくなるので、注意しましょう。