桐間紗路研究所日報

技術以外の話→ https://kirimasyaro.hateblo.jp

pythonで最小二乗法 その1

 このテーマはありきたりだと思うのでn番煎じという感じですが、メモとして


最小二乗法とは

 ぶっちゃけよく知らないんで雑な説明はしたくないんですが、最低限の説明として、まず2次元直交座標上に表せる点データの集合があったとして、その相関を最もよく説明できる


a=\dfrac{\mathrm{Cov}(X,Y)}{\sigma_X^2} \\
b=\mu_Y-A\mu_X

最小二乗法(直線)の簡単な説明 | 高校数学の美しい物語

 という一次直線(y=ax+b)を求める作業ということで良いとおもいます。式が複雑になると萎えてしまうのでコンパクトなものを引用させていただきました。ありがとうございます。
もちろんこれがn次のデータになっていくとどんどんこれが複雑になっていくわけですが、それはまた今度ってことで。

 こういう直線モデルの最小二乗法では、物理の実験なんかで、実験にはつきものである誤差をなるべく少なくするために使ったりするそうです。

 Covというのは共分散といって、偏差の積の平均のことです。偏差ってのは平均からの差のことです。

 わかりにくいと思うので簡単な例を用いて説明すると、完全に相関(?)する、xが1のときyがx*2である点を任意に3つ選び、その相関を検証します
 点(1,2)、点(3,6)、点(8,16)というデータの共分散は、1,3,8の平均は4で、2,6,16の平均は8ですから、偏差の積は-3と-6の積、-1と-2の積、4と8の積というようになります。その平均は(18+2+32)/3=17.333333...と求められます。これが共分散です。あとσxはxの標準偏差です。標準偏差は求めるのが面倒くさい(手順が多いだけで難しくはありませんが)ので、適当なツールを使って求めると2.94392と出てきますので、それを使用します。これでまず求める直線の式の不明な2変数のうちの一つ、a17.3333/(2.9439^2)で17.3333/8.6665=2.000346....と求められます。ここまでくれば切片bを求めるのは簡単で、yの平均マイナス(xの平均かける切片a)で、8-(2*4) = 0 となります。これで前提であるy=x*2(+0)が導けることがわかったとおもいます。(?)

python

 まあ数学の説明は今回メインじゃないんで、この部分は読み飛ばしといても大丈夫、だとおもいます。で、ここでPythonを使っていきます。せっかくなのでさっきのデータ
 点(1,2)、点(3,6)、点(8,16)
 を使います。
 上記の話は

import numpy as np
data = [[1,2],[3,6],[8,16]]

n = len(data)
x = [x[0] for x in data]
y = [x[1] for x in data]
sigmax = np.std(x)
avex = np.mean(x)
avey = np.mean(y)
cov = sum((x - avex)*(y - avey) / n)
a = cov / sigmax ** 2
b = avey - a * avex

print('傾き = ' , a)
print('y軸切片 = ' , b)


と書くことができます。なお標準偏差(np.std)には不偏標準偏差というのもあるのですが、Pythonのデフォルトではそうではないそうです。あとsumは式の途中にリストがあると自動的に繰り返してくれる(?)っぽいので便利ですね。

f:id:copuy:20180520222821j:plain

 求められました。たぶんできてるとおもいます
 次回からはこれを使って実用的なことをしていきたいとおもいます。