Translate

最小二乗法をとりあえず簡単にnumpyで実装する(python)

今回は最小二乗法(一次直線)をpythonで書いた例について紹介したいと思います。


あくまでも今回は初心者甘味がざっくりと簡単にとりあえず実装できるというところまでになります。したがって、細かい式とか原理とかの説明は他の方に譲りたいと思っております。


(私みたいな文系駆け出しの場合だと、いきなり数式が出てくるとドン引きして敵前逃亡してしまう。シグマとかkとかiとか見るだけで頭が痛くなる系(;^ω^))。


最小二乗法を使うと2変数の関係性がなんとなくわかる





では実際に最小二乗法を使うかというと、二つの変数(各データとも言い換えることができる)の関係性をなんとなく把握することができます。

例えば、変数aと変数bはどんな関係性なのだろうというのを見る場合に最小二乗法を使うと二つの変数が直線関係にあるかどうかというのを検証することができます。

ざっくり図で説明するとこんな感じになります。縦軸に変数a、横軸に変数bをとったときにどれだけ直線関係にあるか(線形に収束する程度)を関係性をみることができます。それぞれのプロットが最小二乗法によって計算された直線上に近ければ決定係数(当てはまりの良さみたいなもん)が高くなります。


今回の例では直線の式を最小二乗法で求めていますが、二次曲線や三次曲線でも同じようなことが可能です。これは実際に得られたデータの散布図プロットを見て判断することになると思われます。

実際のpythonコード

今回は、numpyを使って実際に最小二乗法の計算結果を直線回帰式のグラフと、テキストに起こす関数を作っていこうと思います。

実際のコードがこちらになります。

import numpy as np 
#2変数間のプロットに対する回帰式、決定係数を算出する関数

def LS (data1,data2):
    z = np.polyfit(data1,data2,1)
    p = np.poly1d(z)
    r2 = np.corrcoef(data2,p(data1))[0,1]**2
    r2 = str(np.round(r2,3))
    p1 = np.round(p[0],3)
    p2 = np.round(p[1],3)
    f = str ('y = ' + str(p1)+ 'x'+ ' + ' + str(p2))
    
    return z,f,r2
    

こちらのpythonの関数では、まず最小二乗法の計算を行い、その結果を内包した戻り値であるz、r2、そして、回帰式fを返します。前者のzは直線回帰式をmatplotで描写する時に使います。またr2は決定係数になるので、どれだけ二つの変数が関係あるかの指標になります。
最後のfはmatplotlib上で回帰式をテキストで表示するのに使えます。

今回使うのは、np.polyfitというものになります。これは、二つ変数の最小二乗を行い、指定した次数(一次方程式、二次方程式...etc)の回帰式の係数を返してくれます。これらの帰ってきた係数を使って実際に回帰式を書くといった感じです(その部分がnp.poly1d。この部分でnp.polyfitから得られた係数を使って式を作ってくれていると思われ。正直あんま自身ないので間違っていたらすみません。)。

一応こちらで作った関数では、小数点3ケタまでしか表示しないようにしていますが、そこに関しては、np.round()の数字部分を変えれば、桁数は変えることができます。

matplotlibで描写するときはこんな感じ

さっきのnumpyを使った関数の戻り値を使ってmatplotlibでグラフ化する時にはこんな感じのコードになります(一例)。

fig =plt.figure(figsize = (5,5))
ax = fig.add_subplot(1,1,1)
ax.plot(data1,z[0]*data1 + z[1], label = 'Linear Regression',color = 'purple')
ax.plot(data1,data2)
ax.text(5,-10,'R2 = '+ r2, fontsize = 9)
ax.text(5,-15,f, fontsize = 9)

 
生データ(data1、data2)を使って、先ほどの関数でz,r2,fの値を取得したという前提で進めます。折れ線グラフで生データの相関プロットと直線回帰、回帰式および決定係数のテキストボックスを表示する内容になっています。ax.text()のなかの数字は、テキストを表示する位置の座標なので、この辺はご自身で使うデータに合わせて変えてください。

相関プロットを想定しているのでグラフは縦横のアスペクト比を一致させるために、plt.figure()の中のfigsizeを縦横同じ値にしておくとよいでしょう。