2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2021-05-06

 前回に引き続き、Udemy【世界で74万人が受講】基礎から理解し、Pythonで実装!機械学習26のアルゴリズムを理論と実践を通じてマスターしようで学んだ内容をアウトプットしていきたいと思います。

回帰(Regression)とは

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

単回帰

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

y = w_0 + w_1x

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

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

ライブラリのインポート

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

データセットの読み込み

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

独立変数Xと従属変数yの設定

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

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

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

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

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

テスト用データセットを使った予測を実行し予測値とテスト用データセットの値を比較

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 ]]

結果の可視化

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

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

r2_score(y_test, y_pred)

出力結果
0.42394386816456275

重回帰

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

y = w_0 + w_1x_1 + w_2x_2・・・w_nx_n

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

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

ライブラリのインポート

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

データセットの読み込み

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

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

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

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

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

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

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 ]]

モデルの評価

r2_score(y_test, y_pred)

出力結果
0.5892223849182507

多項式回帰

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

y = w_0 + w_1x + w_2x^2

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

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

ライブラリのインポート

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

データセットの読み込み

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

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

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

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

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

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

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 ]]

モデルの評価

r2_score(y_test, y_pred)

出力結果
0.6903318065831567

サポートベクトル回帰

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

qiita_20210506_1.png

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

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

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

ライブラリのインポート

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

データセットの読み込み

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)  # フィーチャースケーリングの為に変換

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

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

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

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

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

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

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

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 ]]

モデルの評価

r2_score(y_test, y_pred)

出力結果
0.6895937132707022

回帰木

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

qiita_20210506_2.png

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

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

qiita_20210506_3.png

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

ライブラリのインポート

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

データセットの読み込み

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

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

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

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

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

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

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]]

モデルの評価

r2_score(y_test, y_pred)

出力結果
0.6019035496385025

ランダムフォレスト(回帰)

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

qiita_20210506_4.png

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

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

ライブラリのインポート

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

データセットの読み込み

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

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

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

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

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

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

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 ]]

モデルの評価

r2_score(y_test, y_pred)

出力結果
0.7734908201180223

回帰分析まとめ

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?