模型對數據的最小平方法擬合¶
這是對物理科學家(例如物理學家、天文學家)或工程師快速介紹 statsmodels
的方法。
為什麼需要這個?
因為大多數 statsmodels
是由統計學家編寫的,他們使用不同的術語,有時使用不同的方法,這使得很難知道哪些類別和函數是相關的,以及它們的輸入和輸出意味著什麼。
[1]:
import numpy as np
import pandas as pd
import statsmodels.api as sm
線性模型¶
假設您在位置 x
處有測量值 y
的數據點,以及測量誤差 y_err
。
您如何使用 statsmodels
將直線模型擬合到此數據?
如需詳細討論,請參閱 Hogg 等人 (2010),“數據分析秘訣:將模型擬合到數據”… 我們將使用他們在表 1 中給出的範例數據。
因此,該模型為 f(x) = a * x + b
,在圖 1 中,他們印出了我們想要重現的結果...此數據「標準加權最小平方法擬合」的最佳擬合參數和參數誤差為: * a = 2.24 +- 0.11
* b = 34 +- 18
[2]:
data = """
x y y_err
201 592 61
244 401 25
47 583 38
287 402 15
203 495 21
58 173 15
210 479 27
202 504 14
198 510 30
158 416 16
165 393 14
201 442 25
157 317 52
131 311 16
166 400 34
160 337 31
186 423 42
125 334 26
218 533 16
146 344 22
"""
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
data = pd.read_csv(StringIO(data), delim_whitespace=True).astype(float)
# Note: for the results we compare with the paper here, they drop the first four points
data.head()
/tmp/ipykernel_4678/2751177292.py:28: FutureWarning: The 'delim_whitespace' keyword in pd.read_csv is deprecated and will be removed in a future version. Use ``sep='\s+'`` instead
data = pd.read_csv(StringIO(data), delim_whitespace=True).astype(float)
[2]:
x | y | y_err | |
---|---|---|---|
0 | 201.0 | 592.0 | 61.0 |
1 | 244.0 | 401.0 | 25.0 |
2 | 47.0 | 583.0 | 38.0 |
3 | 287.0 | 402.0 | 15.0 |
4 | 203.0 | 495.0 | 21.0 |
若要擬合直線,請使用加權最小平方法類別 WLS... 參數稱為:* exog
= sm.add_constant(x)
* endog
= y
* weights
= 1 / sqrt(y_err)
請注意,exog
必須是一個二維陣列,其中包含 x
作為一個列和一個額外的列,其中包含 1。添加此列 1 表示您想要擬合模型 y = a * x + b
,將其省略表示您想要擬合模型 y = a * x
。
您必須使用選項 cov_type='fixed scale'
來告訴 statsmodels
您確實具有絕對尺度的測量誤差。如果您不這樣做,statsmodels
會將權重視為數據點之間的相對權重,並在內部重新縮放它們,以便最佳擬合模型將具有 chi**2 / ndf = 1
。
[3]:
exog = sm.add_constant(data["x"])
endog = data["y"]
weights = 1.0 / (data["y_err"] ** 2)
wls = sm.WLS(endog, exog, weights)
results = wls.fit(cov_type="fixed scale")
print(results.summary())
WLS Regression Results
==============================================================================
Dep. Variable: y R-squared: 0.400
Model: WLS Adj. R-squared: 0.367
Method: Least Squares F-statistic: 193.5
Date: Thu, 03 Oct 2024 Prob (F-statistic): 4.52e-11
Time: 15:50:45 Log-Likelihood: -119.06
No. Observations: 20 AIC: 242.1
Df Residuals: 18 BIC: 244.1
Df Model: 1
Covariance Type: fixed scale
==============================================================================
coef std err z P>|z| [0.025 0.975]
------------------------------------------------------------------------------
const 213.2735 14.394 14.817 0.000 185.062 241.485
x 1.0767 0.077 13.910 0.000 0.925 1.228
==============================================================================
Omnibus: 0.943 Durbin-Watson: 2.901
Prob(Omnibus): 0.624 Jarque-Bera (JB): 0.181
Skew: -0.205 Prob(JB): 0.914
Kurtosis: 3.220 Cond. No. 575.
==============================================================================
Notes:
[1] Standard Errors are based on fixed scale
與 scipy.optimize.curve_fit 比較¶
[4]:
# You can use `scipy.optimize.curve_fit` to get the best-fit parameters and parameter errors.
from scipy.optimize import curve_fit
def f(x, a, b):
return a * x + b
xdata = data["x"]
ydata = data["y"]
p0 = [0, 0] # initial parameter estimate
sigma = data["y_err"]
popt, pcov = curve_fit(f, xdata, ydata, p0, sigma, absolute_sigma=True)
perr = np.sqrt(np.diag(pcov))
print("a = {0:10.3f} +- {1:10.3f}".format(popt[0], perr[0]))
print("b = {0:10.3f} +- {1:10.3f}".format(popt[1], perr[1]))
a = 1.077 +- 0.077
b = 213.273 +- 14.394
與自寫成本函數比較¶
[5]:
# You can also use `scipy.optimize.minimize` and write your own cost function.
# This does not give you the parameter errors though ... you'd have
# to estimate the HESSE matrix separately ...
from scipy.optimize import minimize
def chi2(pars):
"""Cost function."""
y_model = pars[0] * data["x"] + pars[1]
chi = (data["y"] - y_model) / data["y_err"]
return np.sum(chi ** 2)
result = minimize(fun=chi2, x0=[0, 0])
popt = result.x
print("a = {0:10.3f}".format(popt[0]))
print("b = {0:10.3f}".format(popt[1]))
a = 1.077
b = 213.274
非線性模型¶
[6]:
# TODO: we could use the examples from here:
# http://probfit.readthedocs.org/en/latest/api.html#probfit.costfunc.Chi2Regression
上次更新時間:2024 年 10 月 03 日