アンサンブル学習まとめ！！（実装あり）

# はじめに

機械学習で非常に重要となってくるアンサンブル学習。
簡単に内容を理解及び復習できる記事を書きます。

# アンサンブル学習とは

複数のモデル（学習器）を融合させて、1つの学習モデルを作成する手法。

１つのモデルだけで学習させるよりも、複数のモデルを使って組み合わせた方が予測精度が良くなるはず！という考え方から生まれた手法。

## 予測精度が良くなるとは？

予測値と実際値の誤差を最小にすること。

実際に予測精度を確かめるうえで、重要となってくるキーワードが「バイアス」と「バリアンス」！


### バイアス
○実際値と予測値との誤差の平均。
・値が小さければ予測精度高い
・値が大きければ予測精度低い

### バリアンス
○予測値がどれくらい散らばっているのかを示す値。
・値が小さければ予測値がまとまっている
（過学習している可能性が高い）
・値が大きければ予測値が散らばっている

バイアスとバリアンスはトレードオフの関係！！

・予測精度が高ければ、過学習になりやすく
・予測値が散らばっていれば、予測精度が低い

この二つのバランスを調整して行くことが重要となってくる！

# アンザンブル学習の代表的な手法


## ①バギング
異なるデータを抽出（ブートストラップ法）して、複数の異なるモデル（弱学習器）を作成する。その後、作成した複数のモデルの平均を最終的なモデルとする。

※ブートストラップ法：全データの中から同じ数のデータ量をランダムで複数回抽出する。（データを分割する訳ではない）

○特徴
・バリアンスを小さくすることができる。
・並列処理のため、学習時間が短い。
（ブーストラップ法でデータを複数抽出して、複数同時に学習する）

○代表的なモデル
ランダムフォレスト


## ②ブースティング
同じデータに対して何回も学習をし、より精度の高いモデルを構築していく。

○特徴
・バイアスを小さくすることができる。
（バギングよりも良い精度が見込める）
・直列処理のため、学習時間が長い。
（モデルの結果をより改善するモデルを繰り返し構築していく）

○代表的なモデル
XGBoost・LightGBM


## ③スタッキング

複数のモデルを組み合わせてモデルを作成する。

具体的に説明すると、最初に「重回帰分析」、「ランダムフォレスト」、「LightGBM」で予測した値を特徴量として、重回帰分析で予測するという流れになります。

つまり、３つのモデルで予測された3つの予測値が、重回帰分析の入力値になるということ。

どんなモデルを組み合わせるか悩むかと思いますが、決定木系（ランダムフォレスト、XGBoost等）と回帰系（重回帰分析）を組み合わせるのが一般的です。
（異なる系統のモデルを組み合わせることで、単体では発見できない特徴を補ってくれる可能性がある）

○特徴
・予測精度が向上する。
（基本的に単体モデルよりも良い精度が出る）
・結果の解釈、分析が難しくなる。
・学習時間が長くなる

## スタッキングの実装

※【SIGNET】レンタル自転車の利用者数予測を題材にします。
下記リンク
https://signate.jp/competitions/114

データの前処理は省略します。
（簡単なデータの前処理をしているため、結果が異なる場合があります。）

流れとしては、重回帰分析・ランダムフォレスト・LightGBMの予測値を重回帰分析にかけて最終的な予測値とします。（メタモデル）

※メタモデル：第一段階の予測値をまとめるモデル

### データの読み込み

```python.py
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,)
```

### 第一段階での予測値

```pyhon.py
from sklearn.linear_model import LinearRegression #重回帰分析
from sklearn.ensemble import RandomForestRegressor #ランダムフォレスト 
import lightgbm as lgb #LightGBM
# 評価(平均２乗誤差)
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

```

### スタッキングの実装

```python.py
# 第一段階の予測値
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　など