線形回帰直線の求め方

公開日:2018-11-05
最終更新:2018-11-05

はじめに

機械学習のできることとして、回帰と分類に大別できます。まあそのあたりは他の記事様に頼っていただくとして、今回は機械学習の手始めに基本的な手法である線形回帰を紹介します。

回帰直線の決定法

線形回帰でも変数がひとつだけの単回帰、変数が2つ以上の重回帰があるのですが、いきなり変数がたくさん出てくる重回帰を説明するのではなく今回は単回帰のみ説明します。例えば次のような人工データが与えられるとします。
x = [1, 2, 3, 6, 7]
y = [2, 4, 6, 12, 16]
これをプロットしてみると、以下のようになります。
これを見ると、なんだか1つの直線でプロットしてある点以外の横軸に対してもっとももらしい縦軸の値を求められるような直線が引けそうじゃありませんか?(字が汚くて申し訳ない)
引けそうだけど、なんとなくで直線を引いてたら中学校の理科の実験から先に進まないので、最小二乗法という手法で、各点と直線との誤差の2乗が最小化するようにすることで直線の傾きと切片を求めることにします。これにより、横軸のある値での縦軸の値を求められるようになります。

最小二乗法のアルゴリズム

説明変数(今回の横軸)$\bf x$、目的変数(予測したい値、今回の縦軸)$\bf y$とそれらを近似した直線($y = ax + b$)の誤差の2乗の和を$E$とすると、以下のようになります。(数式苦手な人は(4)式と(5)式だけ見れば問題ないです。) $$E = \sum_{i=1}^{n} (ax_i + b - y_i)^2\tag{1}$$ これを最小化するにはEがaとbの関数と考え、2つの変数で微分した値が0になる時を考えます。数式で表すと以下のようになります。 $$\frac{\partial E}{\partial a} =\sum_{i=1}^{n} x_i(ax_i + b - y_i)= 0\tag{2}$$ $$\frac{\partial E}{\partial b} = \sum_{i=1}^{n}(ax_i + b - y_i) =0\tag{3}$$ (3)式を変形してbについて解くと、 $$\sum_{i=1}^{n}ax_i + \sum_{i=1}^{n}b - \sum_{i=1}^{n}y_i = 0$$ $$\sum_{i=1}^{n}b = \sum_{i=1}^{n}(y_i - ax_i)$$ $$nb = \sum_{i=1}^{n}(y_i - ax_i)$$ $$b = \frac{1}{n}\sum_{i=1}^{n}(y_i - ax_i)\tag{4}$$ となり、bを求める式ができました。同様にしてaについても(2)式を変形して式を導出します。 $$\sum_{i=1}^{n} x_i(ax_i + b - y_i) = a\sum_{i=1}^{n} x_i^2 + b\sum_{i=1}^{n} x_i - \sum_{i=1}^{n} x_iy_i$$ ここで(4)式を用いて $$\sum_{i=1}^{n} x_i(ax_i + b - y_i) = a\sum_{i=1}^{n} x_i^2 + \frac{1}{n}\sum_{i=1}^{n}(y_i - ax_i)\sum_{i=1}^{n} x_i - \sum_{i=1}^{n} x_iy_i $$ $$=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\sum_{i=1}^{n}x_i -\sum_{i=1}^{n}x_iy_i $$ $$=a \left(\sum_{i=1}^{n}x_i^2 - \frac{1}{n}\left(\sum_{i=1}^{n}x_i\right)^2\right) + \frac{1}{n}\sum_{i=1}^{n}x_i\sum_{i=1}^{n}y_i - \sum_{i=1}^{n}x_iy_i =0$$ これをaについて解くと、 $$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}\left(\sum_{i=1}^{n}x_i\right)^2}\tag{5}$$ 以上から、(4)式と(5)式を用いれば測定値から最も誤差の小さい直線のパラメータが求められることがわかりました。これをPythonでやっていきたいと思います。

Pythonによる実装

使いやすい数値計算ライブラリNumpyとかしかライブラリmatplotlibを用いて実装を行いました。

import numpy as np
import matplotlib.pyplot as plt

def linear_regression(x, y):
    """xとyのデータ型はnp.array()で定義されていることを要求する。
    """
    n = len(x)
    a = (np.sum(x*y) - np.sum(x) * np.sum(y) / n) / (np.sum(x**2) - (np.sum(x)**2 / n))
    b = (np.sum(y - a * x) )/ n
    return a, b

#メイン処理
x = np.array([1, 2, 3, 6, 7])
y = np.array([2, 4, 6, 12, 16])
a, b = linear_regression(x, y)
f = a * x + b    #直線のy座標を計算
#可視化部分
plt.scatter(x, y)    #点をプロット
plt.plot(x, f)    #直線をプロット
plt.show()

これを実行すると、以下のようになります。
大体プロットした点に近いところを直線が通れていますね。これで計算と実装があっていることが確認できました。

まとめ

今回は機械学習の最も簡単な実装である1入力1出力の線形回帰を実装しました。途中式もかなり丁寧に書いたので、しっかり読めば数学に弱くても理解することができるかと思います。

記事が少しでもいいなと思ったらクラップを送ってみよう!
54
+1
yosakaの技術ブログ。勉強したこととかを書きます

よく一緒に読まれている記事

0件のコメント

ブログ開設 or ログイン してコメントを送ってみよう
目次をみる

技術ブログをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

技術ブログを開設する

Qrunchでアウトプットをはじめよう

Qrunch(クランチ)は、ITエンジニアリングに携わる全ての人のための技術ブログプラットフォームです。

Markdownで書ける

ログ機能でアウトプットを加速

デザインのカスタマイズが可能

技術ブログ開設

ここから先はアカウント(ブログ)開設が必要です

英数字4文字以上
.qrunch.io
英数字6文字以上
ログインする