LoginSignup
3
1

More than 3 years have passed since last update.

機械学習 〜回帰〜 の実装を行う

Last updated at Posted at 2020-12-04

はじめに

最近、機械学習の勉強を初めました。

機械学習アルゴリズムの実装を行っていきたいと思います。

間違っているところなどありましたら、ご指摘をお願いいたします。

参考文献 機械学習のエッセンス

回帰

まず、回帰式を作成するにあたり、データの用意をします。
散布図としてはこのようなデータを用意し、図を作ります。

import numpy as np
import matplotlib.pyplot as plt

x = np.array([1, 2, 4, 6, 8])
y = np.array([1, 3, 3, 4, 6])

plt.scatter(x,y, color = "k")
plt.show()

図を表示させると下のようになります。

Figure_1.png

まず、これらのプロットされた点に対し、原点を通る直線 y = ax で近似します。

xを特徴量、yをターゲットとする。
今回、近似として最小二乗法を用いて評価を行う。
最小二乗法について以下、wikipediaからの引用です。

最小二乗法(さいしょうにじょうほう、さいしょうじじょうほう;最小自乗法とも書く、英: least squares method)は、測定で得られた数値の組を、適当なモデルから想定される1次関数、対数曲線など特定の関数を用いて近似するときに、想定する関数が測定値に対してよい近似となるように、残差の二乗和を最小とするような係数を決定する方法、あるいはそのような方法によって近似を行うことである

そこで、直線で近似した時の誤差の二乗の和を考え、その和を最小にすることを考えます。
ここからは、原点を通る直線で近似をし、その後一般的な直線で近似し、回帰の実装を行っていきます。

原点を通る直線( y = ax )による回帰式

まず原点を通る直線による近似についてです。

次のEを最小化します。
ここで、差を求める際に、原点を通る直線と、実際のプロットとの差ですので、下のような数式で表すことができます。

E = \sum_{i=1}^{n} (ax_i - y_i)^2

ここでEを最小化するために、Eをaで微分をし、微分した関数が0になるところを考えます。

\frac{δE}{δa} = \sum_{i=1}^{n} 2x_i(ax_i - y_i) 
              = 2 (a \sum x_i^2 - \sum x_i y_i) = 0

a = \frac{\sum x_i y_i} {\sum x_i^2} 

機械学習の訓練データは行列で与えられます。 xを特徴量、yをターゲットとし、

x = (x_1, x_2,..., x_n)^T, y = (y_1, y_2, ..., y_n)^T

とします。

このことから、a の分子は xi と yi の内積を計算をし、その和を求める。
a の分母は xi を二乗して、その和を求めているということが上の数式からわかります。

ここで、実際にこの数式を実装して、グラフの表示をしてみたいと思います。

import numpy as np
import matplotlib.pyplot as plt  

def kaikisiki(x ,y):
    a = np.dot(x, y) / (x**2).sum()
    return a

x = np.array([1, 2, 4, 6, 8])
y = np.array([1, 3, 3, 4, 6])
a = kaikisiki(x, y)

plt.scatter(x,y, color = "k")
xmax = x.max()
plt.plot([0, xmax] ,[0, a * xmax], color = "k")
plt.show()

これを実行し、グラフをプロットすると下図のようになりました。

Figure_1.png

この式が回帰式となります。 原点を通る y = ax を回帰式とした時の実装の仕方がわかりました。

一般直線( y = ax + b )による回帰式

今回は一般的な直線で実装を行います。先ほどの原点を通る直線では、原点を必ず通るという制約があるので、近似の精度が下がってしまいます。
そこで、よい近似をするために、 y = ax + b という直線で近似をします。
先ほどと同様に予測式と実際の点との誤差を考えます。
そうすると、二乗誤差は次のような数式になります。

E = \sum_{i=1}^{n} (ax_i + b - y_i)^2

ここでも同様にEをa,bの関数と考えて微分を行い、

\frac{δE}{δa} = 0, \frac{δE}{δb} = 0

という条件を考えます。
まず

\frac{δE}{δa} = 0

について考えます。

\sum_{i=1}^{n} 2ax_i(ax_i + b - y_i) = 0 ・・・ ①

次に

\frac{δE}{δb} = 0

について式変形を行っていくと、

\sum_{i=1}^{n} 2(ax_i + b - y_i) = 0

から、

b = \frac{1}{n} \sum_{i=1}^{n} (y_i - ax_i)  ・・・ ②

という式が導き出せます。この②の条件を①に代入します。
2aは定数なので無視します。

\sum_{i=1}^{n} x_i \Bigl\{ ax_i + {\frac{1}{n} \sum_{i=1}^{n} (y_i - ax_i)} - y_i \Bigr\} 
=  a \sum_{i=1}^{n} x_i^2 + \frac{1}{n} \sum_{i=1}^{n} x_i\sum_{i=1}^{n} y_i - \frac{a}{n}(\sum_{i=1}^{n} x_i)^2 - \sum_{i=1}^{n}x_iy_i
= a \Bigl\{\sum_{i=1}^{n} x_i^2  - \frac{1}{n} (\sum_{i=1}^{n} x_i)^2 \Bigr\} + \frac{1}{n}\sum_{i=1}^{n} x_i\sum_{i=1}^{n} y_i - \sum_{i=1}^{n}x_iy_i =  0

を考えます。

そうすると、

 a =  \frac{\sum_{i=1}^{n}x_iy_i - \frac{1}{n}\sum_{i=1}^{n} x_i\sum_{i=1}^{n} y_i }{\sum_{i=1}^{n} x_i^2  - \frac{1}{n} (\sum_{i=1}^{n} x_i)^2} 

と表すことができます。
よってここで求めたa, bをpythonを用いて実装します。

import numpy as np
import matplotlib.pyplot as plt 


def kaiki2(x, y):
    n = len(x)
    a = ((np.dot(x, y)) - x.sum() * y.sum() / n ) / ((x**2).sum()- x.sum()**2 / n)
    b = (y.sum() - a * x.sum()) / n
    return a, b

x = np.array([1, 2, 4, 6, 7])
y = np.array([1, 3, 6, 4, 8])
a, b = kaikisiki2(x, y)

xmax = x.max()
plt.scatter(x, y, color = "k")
plt.plot([0, xmax], [0, a * xmax + b], color = "k")
plt.show()

import numpy as np
x = np.array([1, 2, 4, 6, 7])
y = np.array([1, 3, 6, 4, 8])

このように実装しました。
プロットを表示させてみます。

Figure_1.png

きちんと表示させることができました。

二次元での回帰の実装方法を理解することができました。
多次元での回帰の実装もしてみたいと思います。

3
1
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
3
1