0
0

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.

ラビットチャレンジ レポート(その4 機械学習-線形回帰・非線形回帰)

Posted at

機械学習

そもそも機械学習モデリングはどのようなフローで行うか?

  • 問題設定:どのような問題を機械学習に解決させるか(そもそも機械学習を使うかどうか)
  • データ選定:どのようなデータを使うか
  • データの前処理:モデルに学習させられるようにデータを変換
  • 機械学習モデルの選定:どの機械学習モデルを利用するか
  • モデルの学習:パラメータ推定
  • モデルの評価:ハイパーパラメータの選定やモデル精度の測定

今回の話は「機械学習モデルの選定」の際に、選択肢となる機械学習モデルの概要と具体的な手法の中身。

線形回帰

回帰問題とは

ある入力値(離散、あるいは連続値)から出力(連続値)を推定する問題。

線形・非線形の違い

ざっくりと言えば、直線で予測するのが線形回帰、曲線で予測するのが非線形回帰。
関数$f$が線形であるためには、以下の2条件を見たす必要がある。

  • 加法性:$f(x+y)=f(x)+f(y)$が成り立つ。
  • 斉次性:定数$k$を用いて、$f(kx) = kf(x)$が成り立つ。

線形回帰モデル

教師あり学習で、入力とパラメータの線形結合によって表されるモデル。
パラメータは

\boldsymbol{w} = (w_1,w_2, \dots,w_m)^\top \in \mathbb{R}^m

で表すことができ、これを用いると、入力系列$x$を用いて出力$y$の推定値$\hat{y}$は以下のように、パラメータと入力の線形結合で書くことができる。

\hat{y} = \boldsymbol{w}^T \boldsymbol{x} + w_0 = \sum_{i=1}^{m}w_i x_i + w_0

このパラメータ$\boldsymbol{w}$が学習するべきパラメータで、最小二乗法によって求める。
最小二乗法は、モデル出力と教師データの二乗誤差の和を最小化することによって、パラメータを求める手法。
ここで出てくる、最小化するべき関数は、**MSE(平均二乗誤差)**と呼ばれ、以下の式で表される。
※$N$はデータ数

\mathrm{MSE}_{train}= \frac{1}{N} \sum_{i=1}^{N}(y_i - \hat{y}_i)^2

この$\mathrm{MSE}_{train}$を最小化するためには、この関数を$\boldsymbol{w}$で偏微分すればよい。
すると、

\cfrac{\partial }{\partial \boldsymbol{w}} \mathrm{MSE}_{train} = 0 \\
\Rightarrow \cfrac{\partial }{\partial \boldsymbol{w}} \left(\frac{1}{N} \sum_{i=1}^{N}(y_i - \hat{y}_i)^2 \right)=0 \\
\Rightarrow \hat{\boldsymbol{w}} = (\bf{X}^\top \bf{X})^{\mathrm{-1}}\bf{X}^\top \boldsymbol{y}

ハンズオン

まずは、適当な1次関数にノイズを載せたデータを作成、pythonのnumpyのみを用いて、線形回帰を最小二乗法を用いて行う

import numpy as np
import matplotlib.pyplot as plt

# ランダムデータ生成
x = np.array(range(0,100,1))
y = np.array([2 * value + 10 + np.random.normal(0,20,1) for value in x])

# 線形回帰をする関数
def LinearRegression(x,y):
    a_child = np.dot(x, y) - x.sum() * y.sum() / len(x)
    a_mother = (x**2).sum() - x.sum()**2 / len(x)
    a = a_child / a_mother
    b = (y.sum() - a * x.sum()) / len(x)
    return a, b

a,b = LinearRegression(x,y)
y_estimate = a * x + b

# 結果を描画
plt.figure(figsize = (8,6))
plt.scatter(x,y, label = 'data')
plt.plot(x, y_estimate, color = 'orange', label = 'regression')
plt.legend(fontsize = 12)
plt.show()

結果が以下。
青いデータ点が作成したデータ。オレンジの直線が線形回帰で求めた直線。

線形回帰-1.png

ボストンの住宅データセットを線形回帰モデルで分析。今度はsklearnを用いる。

from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn import linear_model

boston_raw_data = load_boston()

# 説明変数と目的変数読み込み
X = boston_raw_data.data
y = boston_raw_data.target

# 訓練とテストに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

# 学習
model = linear_model.LinearRegression()
model.fit(X_train, y_train)

# 評価値を見てみる
print(model.score(X_train, y_train))
print(model.score(X_test, y_test))

結果は

0.7730135569264234
0.5892223849182507

となる。予測精度としてはあまり高くはない。

次に、データセットの項目のうち、'CRIM'(犯罪率)と'RM'(部屋数)のみを用いて回帰を行ってみる。

import pandas as pd
import numpy as np

df = pd.DataFrame(X, columns = boston_raw_data.feature_names).assign(MEDV=np.array(y))
X = np.array(df.loc[:,['CRIM','RM']])
y = np.array(df.loc[:,['MEDV']])

# 訓練とテストに分割
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

# 学習
model = linear_model.LinearRegression()
model.fit(X_train, y_train)

# 評価値を見てみる
print(model.score(X_test, y_test))
print(model.predict([[0.3,4]]))

結果は以下。

0.3872466946091787
[[3.72851066]]

精度は落ちた。このモデルでは、犯罪率が0.3で部屋数が4の物件の価格は、約3.72ということになる。(課題)

データの分割とモデルの汎化性能測定

上記のハンズオン中でボストンの住宅価格データセットを用いる際、データの分割を行った。これは、データへの当てはまりの良さではなく、未知のデータに対してどれくらい精度が高いかを測定するため。

データは2つに分割する。

  • 学習用データ:機械学習モデルの学習に利用するデータ
  • 検証用データ:学習済みモデルの精度を検証するためのデータ

学習用データでモデルを学習後、検証用データでモデルの未知のデータへの当てはまりの良さ(汎化性能)を測定する。

非線形回帰

ここまでやってきたような線形回帰で捉えられるデータ構造は限られている。
そこで、学習するパラメータ$\boldsymbol{w}$と目的変数との関係が線形ではない、非線形回帰モデルを用いる。
例えば、以下のようなもの。

y = e^x \\
y = w_0 + w_1 x_1^2 \\
y = w_0 + w_1 \sin{x_1} + w_2 \cos{x_2}

ただし、基底関数法を用いれば、上のようなモデルも線形回帰と同じように扱うことが可能。
例えば、$\phi(x)=x^2$や$\phi(x)=\sin{x}$などを用いると、上記の式も

y = w_0 + w_1 \phi(x_1) + w_2 \phi(x_2) + \dots + w_m \phi(x_m)

と変形できる。この式は、パラメータ$\boldsymbol{w}$については線形な関係が成り立っているので、線形回帰と同じような扱いが可能。

より正確な書き方をすると、

y_i = w_0 + \Sigma_{j=1}^{m}w_j \phi_j(\boldsymbol{x}_i)+ \varepsilon_i

この式における、$\phi_j(\boldsymbol{x}_i)$を基底関数と呼ぶ。
この時よく使われる基底関数は

  • 多項式関数
  • ガウス型基底関数
  • スプライン型/Bスプライン関数

など。

未学習と過学習

回帰を実行するにあたりきをつけなければいけないこと。

  • 未学習:学習データに対して、十分小さな誤差が得られないモデル。もっと表現力の高いモデルを利用する必要がある。
  • 過学習:学習データに対する誤差は小さいが、テストデータに対する誤差が大きいモデル。が奇襲データを増やしたり、モデルの表現力を下げる等の対策が必要。

特に過学習については、基底関数を多く用いると頻発するため、基底関数の数や位置・バンド幅などを調整する必要がある。

正則化法

モデルの複雑さに伴ってパラメータの値が大きくなる正則化項に罰則項を課した関数を最小化。
過学習が起きるモデルのパラメータの値が極端に大きいことが背景にある。
与える罰則項にはいくつか種類がある。

まず、L1ノルムを利用するのがLasso回帰。L1ノルムは以下の形で表される。

||\boldsymbol{w}|| = |w_0| + |w_1| + \dots + |w_m| 

続いて、L2ノルムを利用するのがRidge回帰。L2ノルムは以下の形で表される。

||\boldsymbol{w}||^2 = |w_0|^2 + |w_1|^2 + \dots + |w_m|^2

ハンズオン

まずは、実験に使うデータ作成

# データの作成
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

n=100

def true_func(x):
    z = 1-48*x+218*x**2-315*x**3+145*x**4
    return z 

def linear_func(x):
    z = x
    return z

# 真の関数からノイズを伴うデータを生成

# 真の関数からデータ生成
data = np.random.rand(n).astype(np.float32)
data = np.sort(data)
target = true_func(data)

# ノイズを加える
noise = 0.5 * np.random.randn(n) 
target = target  + noise

# 描画
plt.figure(figsize = (8,6))
plt.scatter(data, target)
plt.title('NonLinear Regression')

非線形回帰-1.png

このデータに対して、sklearnのKernelRidgeクラスを用いて非線形回帰を行う。

from sklearn.kernel_ridge import KernelRidge

data = data.reshape(-1,1)
target = target.reshape(-1,1)

# 学習
model = KernelRidge(alpha=0.0002, kernel='rbf')
model.fit(data, target)

# 推定
p_kridge = model.predict(data)

# グラフ描画
plt.figure(figsize = (8,6))
plt.scatter(data, target, label='data')
plt.plot(data, p_kridge, color='orange', linestyle='-', linewidth=3, markersize=6, label='kernel ridge')
plt.legend()

非線形回帰-2.png

ここで用いたrbfは放射基底関数。予測はデータによく適合しているように見える。

検証方法

学習データと検証データの分け方、パラメータの探し方にも種類がある。

ホールドアウト法

有限のデータを学習用とテスト用の2つに分割し、「学習用データで学習させたモデル(パラメータを求めたモデル)でテスト用データの予測精度を測定」する使い方をする。前述した方法。
手元にデータが大量にない限りは、性能評価があまりよくならない。

クロスバリデーション(交差検証)

手元にあるデータをn分割(nは5や10が多い)、そのうち一つをテスト用、残りを学習用としたモデル評価をn回行う。その精度の平均をモデルの汎化性能とする(この精度の平均をCV値と呼ぶ)。

グリッドサーチ

全てのチューニングパラメータの組み合わせを試して評価値を算出し、最もいい評価値を持つパラメータの組み合わせを選出する。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?