最小二乗法

$N$個のデータ$(x_1,y_1),\cdots,(x_N,y_N)$に対してある直線をあてはたい。
各データを近似できる直線を以下のように定義する。

$
y = ax+b
$

この直線の $a$ と $b$ を求めたい。

点 $(x_n,y_n)$における、近似された直線の$y$軸の値$y’_n$の値は

$
y’_{n} = ax_n + b
$

であるから、実際の点と近似された点との誤差 $t$は

$
t = y’_{n} – ( ax_n + b )
$

と表すことができる。
$t$ はプラスとマイナスの誤差で打ち消されていまうので
この2乗和を考え、各点の誤差の合計を最も小さくする変数 $a,b$ を求められれば良い。

$$
J = \sum_{n=1}^{N}( y’_{n} – ( ax_n + b ) )^2 \tag{1.2}
$$

式(1.2)を最小化する $a,b$ を求める。

式(1.2) をそれぞれ$a$ , $b$ で偏微分で得られた導関数が0となる解を求めれば良い。

$$
\frac{\partial J}{\partial a} = 0 , \frac{\partial J}{\partial b} = 0 ,
$$

具体的に偏微分してみると

$$
\tag{1.3} \frac{\partial J}{\partial a} = a\sum_{n=1}^{N}x_n^2 + b\sum_{n=1}^{N}x_n – \sum_{n=1}^{N}x_ny_n
$$

$$
\tag{1.4} \frac{\partial J}{\partial b} = a\sum_{n=1}^{N}x_n + b\sum_{n=1}^{N}1 – \sum_{n=1}^{N}y_n
$$

解法1

式(1.3)(1.4)は、これは連立1次方程式の形であり、これを解いて$a,b$を求めればよい。

Numpyの連立1次方程式を解く関数を使う

import numpy as np
import random

y = np.array([ 3 * x + 5.0 +random.random()*6 for x in range(10)])
x = np.arange(10)

%matplotlib inline
from matplotlib import pyplot as plt
plt.scatter( [x for x in range (10)], y)
<matplotlib.collections.PathCollection at 0x1163635c0>

sum_XX = np.sum(x**2)
sum_X = np.sum(x)
sum_1 = 10
sum_XY = np.sum( x * y)
sum_Y = np.sum(y)

X= np.array([[sum_XX,sum_X],[sum_X,sum_1]])
Y = np.array([sum_XY,sum_Y])
a,b = np.linalg.solve(X,Y)
print(a)
print(b)
3.011018356776419
7.4796487811962065
%matplotlib inline
from matplotlib import pyplot as plt
plt.scatter( [x for x in range (10)], y)
plt.plot( [x for x in range(10)],[ x*a + b for x in range(10)],c='r')

Scikit-learnのLenearRegressionを使う

from sklearn import linear_model
clf = linear_model.LinearRegression()
train_x = x.reshape(10,1)
train_y = y.reshape(10,1)


c = clf.fit(train_x,train_y)

a = clf.coef_[0][0]
b = clf.intercept_[0]
print (f'a={a},b={b}')
a=3.07969308080669,b=7.640591467908642

Tensorflow を使い 勾配降下法で解く

import tensorflow as tf

x1 = tf.placeholder(tf.float32, [None, 2])
w = tf.Variable(tf.zeros([2, 1]))
y1 = tf.matmul(x1, w)
t = tf.placeholder(tf.float32, [None, 1])
loss = tf.reduce_sum(tf.square(y1 - t))
train_step = tf.train.AdamOptimizer().minimize(loss)

sess = tf.Session()
sess.run(tf.initialize_all_variables())

train_t = np.array(y);
train_t = train_t.reshape([10, 1])


train_x = np.array([ [ 1, i]  for i in range(10)],dtype='float32')

i = 0
for _ in range(100000):
    i += 1
    sess.run(train_step, feed_dict={x1:train_x, t:train_t})
    if i % 10000 == 0:
        loss_val = sess.run(loss, feed_dict={x1:train_x, t:train_t})
        print ('Step: %d, Loss: %f' % (i, loss_val))

w_val = sess.run(w)
print (w_val)

def predict(x):
    result = 0.0
    for n in range(0, 2):
        result += w_val[n][0] * x**n
    return result

fig = plt.figure()
subplot = fig.add_subplot(1, 1, 1)
subplot.set_xlim(1, 10)
subplot.scatter(range(10), train_t)
linex = np.linspace(1, 10, 100)
liney = predict(linex)
subplot.plot(linex, liney,c='r')
plt.show()
WARNING:tensorflow:From <ipython-input-42-15b73738fe80>:11: initialize_all_variables (from tensorflow.python.ops.variables) is deprecated and will be removed after 2017-03-02.
Instructions for updating:
Use `tf.global_variables_initializer` instead.
Step: 10000, Loss: 44.583672
Step: 20000, Loss: 36.941315
Step: 30000, Loss: 36.941315
Step: 40000, Loss: 36.941307
Step: 50000, Loss: 36.941315
Step: 60000, Loss: 36.941319
Step: 70000, Loss: 36.941307
Step: 80000, Loss: 36.941338
Step: 90000, Loss: 36.941315
Step: 100000, Loss: 36.941322
[[7.3787937]
 [3.138206 ]]