機械学習を学んでみたのでそのまとめ②回帰

　前回に引き続き、Udemy[【世界で74万人が受講】基礎から理解し、Pythonで実装！機械学習26のアルゴリズムを理論と実践を通じてマスターしよう](https://www.udemy.com/course/ml-with-python/)で学んだ内容をアウトプットしていきたいと思います。

# 回帰(Regression)とは
回帰モデルは、あるデータ（独立変数）からある値（従属変数）を予測する際に使われます。
例：独立変数の年齢、階級から従属変数である給料を予測する。
ここでは、線形回帰（単回帰、重回帰）、多項式回帰、サポートベクトル回帰、回帰木、ランダムフォレストの手法を学んだ。

## 単回帰
単回帰とは、ざっくり言うと以下の式を作って独立変数$x$から従属変数$y$を求める手法です。もっとも当てはまりの良い直線を引くために最小二乗法を用いて$w_0$と$w_1$を算出します。

```math
y = w_0 + w_1x
```

とりあえず、学んだ内容でScikit-learnのデータセットのボストン市の住宅価格を使って、RM（平均部屋数）を独立変数、MEDV（住宅価格）を従属変数として単回帰分析をしたいと思います。

単回帰は機械学習の中でも一番シンプルなので機械学習の流れを掴むのにはいいと思います。

ライブラリのインポート

```python
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
```

データセットの読み込み

```python
boston = load_boston()
boston_data = pd.DataFrame(boston.data, columns = boston.feature_names).assign(MEDV=np.array(boston.target))
```
独立変数Xと従属変数yの設定

```python
X = boston_data[['RM']].values
y = boston_data['MEDV'].values
```

訓練用データセットとテスト用データセットへの分割(8:2)

```python
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
```

訓練用データセットを使った学習

```python
reg = LinearRegression()
reg.fit(X_train, y_train)
```
テスト用データセットを使った予測を実行し予測値とテスト用データセットの値を比較

```python
y_pred = reg.predict(X_test)
np.set_printoptions(precision=2)
print(np.concatenate((y_pred.reshape(len(y_pred), 1), y_test.reshape(len(y_test), 1)), 1))
```

`出力結果`
[[22.9  22.6 ]
 [21.81 50.  ]
 [23.28 23.  ]
・・・
（省略）
・・・
 [17.35 18.7 ]
 [23.3  28.1 ]
 [24.23 19.8 ]]

結果の可視化

```python
plt.scatter(X_train, y_train, color = 'red', label='train_data')
plt.plot(X_train, reg.predict(X_train), color = 'blue', label='predict_data')
plt.title('RM vs MEDV')
plt.xlabel('RM')
plt.ylabel('MEDV')
plt.legend()
plt.show()
```
![qiita_20210505_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/e789cd35-e550-40c8-96b8-b8752f197c5f.png)

決定係数で回帰の当てはまりの良さを確認

```python
r2_score(y_test, y_pred)
```

`出力結果`
0.42394386816456275





## 重回帰
重回帰とは、ざっくり言うと単回帰で扱った独立変数が１つから２つ以上に増えたもので、２つの場合でいうと独立変数$x_1$, $x_2$から従属変数$y$を求める手法です。単回帰は平面の図で表わせましたが、重回帰で独立変数が増えれば増えるほど高次元になっていくので図で表すのは不可能になってきます。

```math
y = w_0 + w_1x_1 + w_2x_2・・・w_nx_n
```

また、線形回帰の前提として以下の５つの条件を満たさない場合は線形回帰を使うべきではないようです。
1.線形性
2.内生性がないこと
3.正規性と同分散性
4.自己相関がないこと
5.多重共線性がないこと

とりあえず、ここでも学んだ内容でScikit-learnのデータセットのボストン市の住宅価格を使って、MEDV（住宅価格）以外のデータすべてを独立変数、MEDV（住宅価格）を従属変数として重回帰分析をしたいと思います。

ライブラリのインポート

```python
import numpy as np
import pandas as pd
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.metrics import r2_score
```

データセットの読み込み

```python
boston = load_boston()
boston_data = pd.DataFrame(boston.data, columns = boston.feature_names).assign(MEDV=np.array(boston.target))
X = boston_data.iloc[:, :-1].values
y = boston_data.iloc[:, -1].values
```

 訓練用データとテスト用へデータセットの分割

```python
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
```

訓練用データを使ったモデルの訓練

```python
reg = LinearRegression()
reg.fit(X_train, y_train)
```

テスト用データを使った結果の予測

```python
y_pred = reg.predict(X_test)
np.set_printoptions(precision=2)
print(np.concatenate((y_pred.reshape(len(y_pred), 1), y_test.reshape(len(y_test), 1)), 1))
```

`出力結果`
[[24.89 22.6 ]
 [23.72 50.  ]
 [29.36 23.  ]
・・・
（省略）
・・・
 [17.94 18.7 ]
 [25.31 28.1 ]
 [22.37 19.8 ]]

モデルの評価

```python
r2_score(y_test, y_pred)
```

`出力結果`
0.5892223849182507


## 多項式回帰
その名の通り以下のような多項の式で回帰分析を行います。

```math
y = w_0 + w_1x + w_2x^2
```

線形回帰の当てはまりが良くない時に使ったりするけど、直感的にデータを見て多項式回帰の方が当てはまりが良いとわかることは少ないようです。

とりあえず、ここでも学んだ内容でScikit-learnのデータセットのボストン市の住宅価格を使って、MEDV（住宅価格）以外のデータすべてを独立変数、MEDV（住宅価格）を従属変数として多項式分析を用いて回帰分析をしたいと思います。

ライブラリのインポート

```python
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn.preprocessing import PolynomialFeatures
from sklearn.metrics import r2_score
```

データセットの読み込み

```python
boston = load_boston()
boston_data = pd.DataFrame(boston.data, columns = boston.feature_names).assign(MEDV=np.array(boston.target))
X = boston_data.iloc[:, :-1].values
y = boston_data.iloc[:, -1].values
```

 訓練用データとテスト用へデータセットの分割

```python
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
```

訓練用データを使ったモデルの訓練

```python
poly_reg = PolynomialFeatures(degree = 2)
X_poly = poly_reg.fit_transform(X_train)
reg = LinearRegression()
reg.fit(X_poly, y_train)
```

テスト用データを使った結果の予測

```python
y_pred = reg.predict(poly_reg.transform(X_test))
np.set_printoptions(precision=2)
print(np.concatenate((y_pred.reshape(len(y_pred),1), y_test.reshape(len(y_test),1)),1))
```

`出力結果`
[[21.53 22.6 ]
 [28.83 50.  ]
 [27.24 23.  ]
・・・
（省略）
・・・
 [15.17 18.7 ]
 [25.74 28.1 ]
 [19.24 19.8 ]]

モデルの評価

```python
r2_score(y_test, y_pred)
```

`出力結果`
0.6903318065831567


## サポートベクトル回帰
サポートベクトルとは線形を前提とした場合、まずはデータに対して当てはまりの良い直線を引く、その前後に平行な直線を引いてそこに乗るベクトルの事をサポートベクトルと呼ぶ。
当てはまりの良い線からサポートベクトルの距離ε(イプシロン)はハイパーパラメータでサポートベクトルマシンを使う際にこちらで指定する必要がある。

![qiita_20210506_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/f0ce3cfd-abdd-67ba-18a4-8a76db96b267.png)


サポートベクトルによって支えられた直線の外にあるデータとの距離が最小になるような一番当てはまりの良い線を算出する。
具体的には以下の式が最小になるようにする。


```math
C\sum\xi + \frac{1}{2} \begin{Vmatrix} w \end{Vmatrix}^2
```

それでは、ここでも学んだ内容でScikit-learnのデータセットのボストン市の住宅価格を使って、MEDV（住宅価格）以外のデータすべてを独立変数、MEDV（住宅価格）を従属変数としてサポートベクトル回帰を用いて回帰分析をしたいと思います。

ライブラリのインポート

```python
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVR
from sklearn.metrics import r2_score
```

データセットの読み込み

```python
boston = load_boston()
boston_data = pd.DataFrame(boston.data, columns = boston.feature_names).assign(MEDV=np.array(boston.target))
X = boston_data.iloc[:, :-1].values
y = boston_data.iloc[:, -1].values
y = y.reshape(len(y),1)  # フィーチャースケーリングの為に変換
```

 訓練用データとテスト用へデータセットの分割

```python
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
```

フィーチャースケーリング

```python
sc_X = StandardScaler()
sc_y = StandardScaler()
X_train = sc_X.fit_transform(X_train)
y_train = sc_y.fit_transform(y_train)
```

訓練用データを使ったモデルの訓練

```python
reg = SVR(kernel = 'rbf')
reg.fit(X_train, y_train)
```

テスト用データを使った結果の予測

```python
y_pred = sc_y.inverse_transform(reg.predict(sc_X.transform(X_test)))
np.set_printoptions(precision=2)
print(np.concatenate((y_pred.reshape(len(y_pred),1), y_test.reshape(len(y_test),1)),1))
```

`出力結果`
[[23.93 22.6 ]
 [21.53 50.  ]
 [25.11 23.  ]
・・・
（省略）
・・・
 [17.71 18.7 ]
 [25.28 28.1 ]
 [19.77 19.8 ]]

モデルの評価

```python
r2_score(y_test, y_pred)
```

`出力結果`
0.6895937132707022


## 回帰木
まず、決定木（Decision Tree）とは以下のように条件分岐を繰り返すことで分類や回帰を行うモデルで回帰に使う場合を回帰木と言います。

![qiita_20210506_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/61b908d7-f269-1b1f-ac8d-e03a89cb8b71.png)

回帰木の場合は下のグラフのように従属変数の最小2乗法で以下の式が最小になるように独立変数でグループ分けをする線を引く。

```math
\sum(\hat{y}-y)^2
```

![qiita_20210506_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/c185cad6-6004-176e-d18c-3edb24f9c5f9.png)

それでは、ここでも学んだ内容でScikit-learnのデータセットのボストン市の住宅価格を使って、MEDV（住宅価格）以外のデータすべてを独立変数、MEDV（住宅価格）を従属変数として回帰木を用いて回帰分析をしたいと思います。

ライブラリのインポート

```python
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import r2_score
```

データセットの読み込み

```python
boston = load_boston()
boston_data = pd.DataFrame(boston.data, columns = boston.feature_names).assign(MEDV=np.array(boston.target))
X = boston_data.iloc[:, :-1].values
y = boston_data.iloc[:, -1].values
```

 訓練用データとテスト用へデータセットの分割

```python
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
```

訓練用データを使ったモデルの訓練

```python
reg = DecisionTreeRegressor(random_state = 0)
reg.fit(X_train, y_train)
```

テスト用データを使った結果の予測

```python
y_pred = reg.predict(X_test)
np.set_printoptions(precision=2)
print(np.concatenate((y_pred.reshape(len(y_pred),1), y_test.reshape(len(y_test),1)),1))
```

`出力結果`
[[23.7 22.6]
 [20.8 50. ]
 [20.6 23. ]
・・・
（省略）
・・・
 [19.7 18.7]
 [25.  28.1]
 [20.1 19.8]]

モデルの評価

```python
r2_score(y_test, y_pred)
```

`出力結果`
0.6019035496385025


## ランダムフォレスト（回帰）

ランダムフォレストとは独立して学習させた多数の決定木を沢山重ねて、その中で多数決をとってどの値を用いるのかを決定することができる。

![qiita_20210506_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350321/90ee00e5-9a6d-f461-69a9-25e69ab9f25b.png)


ランダムフォレストのパラメータとしては定木の本数があり多ければ多いほど性能が安定しますが､一方で学習時間や予測時間も増加していきます｡

それでは、ここでも学んだ内容でScikit-learnのデータセットのボストン市の住宅価格を使って、MEDV（住宅価格）以外のデータすべてを独立変数、MEDV（住宅価格）を従属変数としてランダムフォレストを用いて回帰分析をしたいと思います。

ライブラリのインポート

```python
import numpy as np
import pandas as pd
import seaborn as sns
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import r2_score
```

データセットの読み込み

```python
boston = load_boston()
boston_data = pd.DataFrame(boston.data, columns = boston.feature_names).assign(MEDV=np.array(boston.target))

X = boston_data.iloc[:, :-1].values
y = boston_data.iloc[:, -1].values
```

 訓練用データとテスト用へデータセットの分割

```python
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)
```

訓練用データを使ったモデルの訓練

```python
reg = RandomForestRegressor(n_estimators = 100, random_state = 0)
reg.fit(X_train, y_train)
```

テスト用データを使った結果の予測

```python
y_pred = reg.predict(X_test)
np.set_printoptions(precision=2)
print(np.concatenate((y_pred.reshape(len(y_pred),1), y_test.reshape(len(y_test),1)),1))
```

`出力結果`
[[23.93 22.6 ]
 [29.11 50.  ]
 [22.14 23.  ]
・・・
（省略）
・・・
 [18.91 18.7 ]
 [23.72 28.1 ]
 [20.35 19.8 ]]

モデルの評価

```python
r2_score(y_test, y_pred)
```

`出力結果`
0.7734908201180223

## 回帰分析まとめ

| モデル | 長所 | 短所 |
|:-:|:-:|:-:|
| 線形回帰  | 特徴量の関係性がわかりやすい  | 線形回帰の前提条件を満たさないと使えない  |
| 多項式回帰 | 非線形の問題に対して良い当てはまりをする  | 多項式の次数の設定次第で精度が変わる |
| サポートベクトル回帰  | 適用が簡単で高い精度が出やすい  | フィーチャースケーリング（標準化）が必要  |
| 回帰木 | 線形、非線形どちらでも使える  | データ数が少ないと精度が低くなりがち  |
| ランダムフォレスト | 線形、非線形どちらでも使え、精度も高い  | 使用する決定木の数を指定する必要があり、多くすると精度が高くなるが学習時間や予測時間も増加する  |