こんな感じに傾きが同じ複数のデータ列があるときに,傾き
データ
研究で必要になって計算したのですがいろいろ計算をミスって手こずったので,せっかくなので残しておこうと思います.
ニッチなシチュエーションですが,アレニウスプロットのように両対数をとって傾きからべきを求めるような解析なんかには使えるかもしれません.
まず計算の参考にするため,「普通の」最小二乗法の計算を追ってみます.
こちらの計算は[1]の記事を参考にさせていただきました.
最小二乗法による線形回帰は,データが直線
従っているところにノイズが乗っていると考えて,このノイズを最小化する
各データ点を
ここで「ノイズの大きさ」を「差の絶対値」などではなく「差の2乗」で表すのは正規分布の最尤推定との関連と,後述するように微分できた方が計算が簡単であるという都合によるものです.
さて,最小化すべき関数
すなわち最小点は極小点と一致するため
よって,
を解くと,(2)式を変形して,
ここで,
となります.これを(1)式に代入して整理すると,
このようにして,
ちなみに,誤差の大きさは正規分布の最尤推定問題を解くことで
冒頭の図1のように,
と定式化できます.
シグマが増えてややこしくなりましたが,最小化すべき関数
の
(4)式は各
です.
これを(3)式に代入し整理すると,
となります.
となるので少し式が違いますね.
結論:
この場合も,同様に正規分布の最尤推定により
文字式ばかりだとピンとこないので,実際に数値計算も行ってみます.
プロット
import numpy as np
np.random.seed(42)
a = 1.5
b1 = 0.5
b2 = 2.1
b3 = 4.3
s = 0.5
x1 = [0.4, 2.0, 2.7, 3.6, 4.2]
x2 = [0.2, 1.1, 2.9, 3.6, 4.7]
x3 = [0.0, 2.0, 2.8, 3.2, 4.2]
y1 = [a*x+b1+np.random.normal(0,s) for x in x1]
y2 = [a*x+b2+np.random.normal(0,s) for x in x2]
y3 = [a*x+b3+np.random.normal(0,s) for x in x3]
X = np.array([x1,x2,x3])
Y = np.array([y1,y2,y3])
X
,Y
とすると,大きさ
単に+
,*
で演算すると成分ごとの演算となり,.mean(axis=1)
,.mean()
(注:0-indexed)で得られるため,
a_hat = ((X*Y).mean(axis=1)-X.mean(axis=1)*Y.mean(axis=1)).mean() / ((X**2).mean(axis=1) - X.mean(axis=1)**2).mean()
# => 1.574510913222147
b_hat = Y.mean(axis=1) - a_hat*X.mean(axis=1)
# => array([0.07364212, 1.35999338, 4.42261194])
点が少ないのでブレがありますが,一応それらしい値が得られました.
ところでこの解析は,モデルとして階層的なものを最尤推定で求めているため,パラメータ推定として不適切です.
現に,「それっぽい値が出ている」ということしかわからず,推定値がどれくらいの分散を持っているのかすら求められていませんね.
本当はパラメータの分布をベイズ推定で求め,詳しく解析する必要があります.
が,計算が大変なのでそれはまた別の機会に……