はじめに
最近、機械学習の勉強を初めました。
機械学習アルゴリズムの実装を行っていきたいと思います。
間違っているところなどありましたら、ご指摘をお願いいたします。
参考文献 機械学習のエッセンス
回帰
まず、回帰式を作成するにあたり、データの用意をします。
散布図としてはこのようなデータを用意し、図を作ります。
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()
図を表示させると下のようになります。
まず、これらのプロットされた点に対し、原点を通る直線 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()
これを実行し、グラフをプロットすると下図のようになりました。
この式が回帰式となります。 原点を通る 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])
このように実装しました。
プロットを表示させてみます。
きちんと表示させることができました。
二次元での回帰の実装方法を理解することができました。
多次元での回帰の実装もしてみたいと思います。