はじめに
機械学習で非常に重要となってくるアンサンブル学習。
簡単に内容を理解及び復習できる記事を書きます。
アンサンブル学習とは
複数のモデル(学習器)を融合させて、1つの学習モデルを作成する手法。
1つのモデルだけで学習させるよりも、複数のモデルを使って組み合わせた方が予測精度が良くなるはず!という考え方から生まれた手法。
予測精度が良くなるとは?
予測値と実際値の誤差を最小にすること。
実際に予測精度を確かめるうえで、重要となってくるキーワードが「バイアス」と「バリアンス」!
バイアス
○実際値と予測値との誤差の平均。
・値が小さければ予測精度高い
・値が大きければ予測精度低い
バリアンス
○予測値がどれくらい散らばっているのかを示す値。
・値が小さければ予測値がまとまっている
(過学習している可能性が高い)
・値が大きければ予測値が散らばっている
バイアスとバリアンスはトレードオフの関係!!
・予測精度が高ければ、過学習になりやすく
・予測値が散らばっていれば、予測精度が低い
この二つのバランスを調整して行くことが重要となってくる!
アンザンブル学習の代表的な手法
①バギング
異なるデータを抽出(ブートストラップ法)して、複数の異なるモデル(弱学習器)を作成する。その後、作成した複数のモデルの平均を最終的なモデルとする。
※ブートストラップ法:全データの中から同じ数のデータ量をランダムで複数回抽出する。(データを分割する訳ではない)
○特徴
・バリアンスを小さくすることができる。
・並列処理のため、学習時間が短い。
(ブーストラップ法でデータを複数抽出して、複数同時に学習する)
○代表的なモデル
ランダムフォレスト
②ブースティング
同じデータに対して何回も学習をし、より精度の高いモデルを構築していく。
○特徴
・バイアスを小さくすることができる。
(バギングよりも良い精度が見込める)
・直列処理のため、学習時間が長い。
(モデルの結果をより改善するモデルを繰り返し構築していく)
○代表的なモデル
XGBoost・LightGBM
③スタッキング
複数のモデルを組み合わせてモデルを作成する。
具体的に説明すると、最初に「重回帰分析」、「ランダムフォレスト」、「LightGBM」で予測した値を特徴量として、重回帰分析で予測するという流れになります。
つまり、3つのモデルで予測された3つの予測値が、重回帰分析の入力値になるということ。
どんなモデルを組み合わせるか悩むかと思いますが、決定木系(ランダムフォレスト、XGBoost等)と回帰系(重回帰分析)を組み合わせるのが一般的です。
(異なる系統のモデルを組み合わせることで、単体では発見できない特徴を補ってくれる可能性がある)
○特徴
・予測精度が向上する。
(基本的に単体モデルよりも良い精度が出る)
・結果の解釈、分析が難しくなる。
・学習時間が長くなる
スタッキングの実装
※【SIGNET】レンタル自転車の利用者数予測を題材にします。
下記リンク
https://signate.jp/competitions/114
データの前処理は省略します。
(簡単なデータの前処理をしているため、結果が異なる場合があります。)
流れとしては、重回帰分析・ランダムフォレスト・LightGBMの予測値を重回帰分析にかけて最終的な予測値とします。(メタモデル)
※メタモデル:第一段階の予測値をまとめるモデル
データの読み込み
import pandas as pd
import numpy as np
# データの読み込み
df = pd.read_csv('train.tsv', delimiter = '\t')
df = df.drop(['id', 'dteday', 'yr', 'atemp'],axis =1)
### 必要に応じてデータの前処理をしてください。
# 説明変数
train = df.drop('cnt', axis=1)
# 目的変数
test = df['cnt']
# データを3つに分割
from sklearn.model_selection import train_test_split
X_train,X_test, y_train, y_test = train_test_split(train, test, test_size=0.2, random_state=0)
X_train, X_valid, y_train, y_valid = train_test_split(X_train, y_train, test_size=0.2, random_state=0)
print(X_train.shape)
print(X_valid.shape)
print(X_test.shape)
print(y_train.shape)
print(y_valid.shape)
print(y_test.shape)
(5532, 8)
(1384, 8)
(1729, 8)
(5532,)
(1384,)
(1729,)
第一段階での予測値
from sklearn.linear_model import LinearRegression #重回帰分析
from sklearn.ensemble import RandomForestRegressor #ランダムフォレスト
import lightgbm as lgb #LightGBM
# 評価(平均2乗誤差)
from sklearn.metrics import mean_squared_error
# モデルのインスタンス
model_1 = LinearRegression()
model_2 = RandomForestRegressor()
model_3 = lgb.LGBMRegressor()
# モデルの学習
model_1.fit(X_train, y_train)
model_2.fit(X_train, y_train)
model_3.fit(X_train, y_train)
# 予測値の作成
pred_1 = model_1.predict(X_test)
pred_2 = model_2.predict(X_test)
pred_3 = model_3.predict(X_test)
# 各モデル個別の予測精度を平均二乗誤差で確認
print ("重回帰分析の平均2乗誤差: {:.4f}".format(mean_squared_error(y_test, pred_1)))
print ("ランダムフォレストの平均2乗誤差: {:.4f}".format(mean_squared_error(y_test, pred_2)))
print ("LightGBMの平均2乗誤差: {:.4f}".format(mean_squared_error(y_test, pred_3)))
重回帰分析の平均2乗誤差: 6825.7104
ランダムフォレストの平均2乗誤差: 4419.4774
LightGBMの平均2乗誤差: 4043.2921
スタッキングの実装
# 第一段階の予測値
first_pred_1 = model_1.predict(X_valid)
first_pred_2 = model_2.predict(X_valid)
first_pred_3 = model_3.predict(X_valid)
# 第一段階の予測値をまとめる(メタモデルの特徴量)
stack_pred = np.column_stack((first_pred_1,first_pred_2,first_pred_3))
# メタモデルの作成
meta_model = LinearRegression()
# 第一段階の予測値の答え = y_valid
meta_model.fit(stack_pred, y_valid)
# 事前に予測しておいた値でスタッキングの精度を確認する
stack_test_pred = np.column_stack((pred_1, pred_2, pred_3))
meta_test_pred = meta_model.predict(stack_test_pred)
print ("メタモデルの平均2乗誤差: {:.4f}".format(mean_squared_error(y_test, meta_test_pred)))
メタモデルの平均2乗誤差: 4030.9495
おわりに
単体でのモデルよりも少しだけ予測精度が良くなりました。
○改善点
・それぞれのモデルのパラメータの調整
・第一段階のモデルを変えるor増やす
・モデルの数はそのままでパラメータを変えたバージョンを増やす
exランダムフォレスト n_estimators=50, n_estimators=100, n_estimators=1000 など