アンサンブル学習(ランダムフォレスト)をざっくりと理解する

アンサンブル学習についての理論などざっくりと勉強したためメモとして残しておきます。


#アンサンブル学習とは
複数の学習器を組み合わせてより良い予測を得ようとするテクニック。単一のモデルを単独で使うより大抵の場合、良い結果が得られる。概要などは[こちらのページ](https://www.codexa.net/what-is-ensemble-learning/)が参考になりました。

#モデルの種類
##バギング(ブーストラップ)

訓練データからランダムにn個のデータをサンプリングする手法。
訓練データから大きさnのブーストラップデータ集合をN個生成する。それらのデータを用いてN個の予測モデルを作ると、それぞれの予測値はYn(X)となる。したがって、バギングを使ったモデルの最終的な予測値は次のようになる。

![スクリーンショット 2019-03-03 19.02.45.png](https://qiita-image-store.s3.amazonaws.com/0/346585/d76ed411-805d-5205-3e37-92b95a873c50.png)


N個の予測値の平均を取っている。
ただし、すべてのデータが正常であれば正しく予測できるが、すべて外れ値、もしくは外れ値が多いデータだと精度が低下する。つまりそれぞれのモデルの重要度を考慮できていない。

##スタッキング

バギングでは、N個の予測値の単純平均で考えているため、個々の予測値を均等で評価しており、それぞれのモデルの重要度を考慮できていない。
スタッキングでは、個々の予測値の加重平均を最終的な予測値とし、モデルごとの重要度を考慮することができる。よって、最終的な予測値は次のようになる。

![スクリーンショット 2019-03-03 20.17.14.png](https://qiita-image-store.s3.amazonaws.com/0/346585/5a37d605-c554-2d9b-7a89-538f747f8289.png)

##バンピング

複数の予測値から最もよいモデルを探すための手法。
ブーストラップデータ集合を使ってN個のモデルを生成し、それらの元の訓練データをに当てはめ、予測値を最小にするモデルを最良のモデルとして選ぶ。
質の悪いデータを用いて望ましくない解が得られてしまった時、それらのデータを除いたブーストラップデータ集合によって、より良い解が得られる。

##ランダムフォレスト

バギングのベース学習器として決定木を用いた手法。
具体的なアルゴリズムは以下の通り。

1,訓練データからN個のブーストラップデータ集合を取り出す。

2,これらのデータを使ってN個の木**Tn**を生成する。この時、**p**個の特徴量から**m**個だけランダムに選ぶ。

3,回帰の場合は平均を、分類の場合は多数決を使って最終的な予測値とする。


- ベース学習器に決定木を用いる理由

バギングの基本的な考え方は、分散大、バイアス小のモデルを複数組み合わせて誤差を減らすことで、決定木はバギングのベース学習器として理想的な分散大、バイアス小のモデルである。
※分散大、バイアス小・・・決定木、最近傍法などの複雑なモデル。

##ランダムフォレストを実装

今回も線形分離不可能であるmake_moonsを使用していきます。

```py
#必要なライブラリをインポート
import numpy as np 
import matplotlib.pyplot as plt
from sklearn.datasets import make_moons
from matplotlib.colors import ListedColormap

#データを分割
moons = make_moons(n_samples=200, noise=0.2, random_state=0)
X = moons[0]
y = moons[1]

#グラフを描画
def plot_decision_boundary(model, X, y, margin=0.3):
    _x1 = np.linspace(X[:,0].min() -margin, X[:, 0].max() +margin, 100)
    _x2 = np.linspace(X[:, 1].min() -margin, X[:, 1].max() +margin, 100)
    x1, x2 = np.meshgrid(_x1, _x2)
    X_new = np.c_[x1.ravel(), x2.ravel()]
    y_pred = model.predict(X_new).reshape(x1.shape)
    custom_cmap = ListedColormap(["mediumblue", "orangered"])
    plt.contourf(x1, x2, y_pred, alpha=0.3, cmap=custom_cmap)
    
def plot_datasets(X, y):
    plt.plot(X[:, 0][y==0], X[:, 1][y==0], "bo", ms=15)
    plt.plot(X[:, 0][y==1], X[:, 1][y==1], "r^", ms=15)
    plt.xlabel("$x_0$", fontsize=30)
    plt.ylabel("$x_1$", fontsize=30, rotation=0)
    
plt.figure(figsize=(12, 8))
plot_datasets(X, y)
plt.show()
```
![スクリーンショット 2019-03-03 20.44.35.png](https://qiita-image-store.s3.amazonaws.com/0/346585/3b2b898c-ae8c-fc10-97dc-1c7af789aa71.png)

すると上記のような線形分離不可能なグラフが描画されます。
次にランダムフォレストで学習させます。

```py
#必要なライブラリをインポート
from sklearn.ensemble import RandomForestClassifier

#学習
random_forest = RandomForestClassifier(n_estimators=100, random_state=0).fit(X_train, y_train)#n_estimators組み合わせの数

#グラフを描画
plt.figure(figsize=(12, 8))
plot_decision_boundary(random_forest, X ,y)
plot_datasets(X, y)
plt.show()
```

![スクリーンショット 2019-03-03 20.51.11.png](https://qiita-image-store.s3.amazonaws.com/0/346585/dd146e46-340d-bc5f-9c89-76152c8e6e97.png)

グラフを見るとベース学習器が決定木でもあるにも関わらず、予測面が曲線(滑らかに)で表現されており、決定木のデメリットが解消されていることがわかります。

ちなみに決定木を用いて学習すると以下のようなグラフになります。

![スクリーンショット 2019-03-03 20.54.51.png](https://qiita-image-store.s3.amazonaws.com/0/346585/685d0dd8-7dfe-89ad-87a3-19a1f41b9569.png)