我有一些来自实验室的数据,我正在将其拟合到函数中
f(s, params) = amp * (s/sp) / (1 + s/sp + 1.041) + bg(不知道如何输入设置)
我在
absolute_sigma=True
上设置curve_fit
来获得参数(sp、amp、bg)的绝对不确定性,但是从np.sqrt(np.diag(pcov))
计算出的误差似乎不合理。请参阅下面的图。蓝点是数据。红线是f(s, *popt)
。绿线将最佳 sp 值替换为 sp - 这是根据 np.sqrt(np.diag(pcov))
计算得出的误差。橙色线是 sp + 相同的值。
我预计 +/- 线会比红线更紧。
这是一个最小的例子:
# Function for fitting
def scattering_rate(s, sp, amp, bg):
return amp * (s/sp) / (1 + s/sp + (-20/19.6)**2) + bg
# data
s = np.array([0.6, 1.2, 2.3, 4.3, 8.1, 15.2, 28.5, 53.4])
y = np.array([8.6, 8.5, 8.9, 9.5, 10.6, 12.6, 15.5, 18.3])
# Fit data to saturated scattering rate
popt, pcov = curve_fit(scattering_rate, s, y, absolute_sigma=True)
print('Fit parameters', popt)
print('Fit uncertainties', np.sqrt(np.diag(pcov)))
# Construct fit from optimized parameters
fit_s = np.linspace(np.min(s), np.max(s), 100)
fit = scattering_rate(fit_s, *popt)
# Consider one error difference in sp value
fit_plus_err = saturation_power(fit_s, popt[0] + np.sqrt(np.diag(pcov))[0], popt[1], popt[2])
fit_minus_err = saturation_power(fit_s, popt[0] - np.sqrt(np.diag(pcov))[0], popt[1], popt[2])
# Plot
plt.plot(s, y, '-o', markeredgecolor='k', label='data')
plt.plot(fit_s, fit_plus_err, label='sp + err')
plt.plot(fit_s, fit_minus_err, label='sp - err')
plt.plot(fit_s, fit, '-r', label='opt sp')
plt.xlabel('s')
plt.ylabel('y')
plt.legend()
plt.grid()
plt.show()
编辑
根据@jlandercy的回答,我们需要原始数据的误差线,即
y_err = array([0.242, 0.231, 0.282, 0.31 , 0.373])
。包括curve_fit
的sigma
论证中,结果看起来好多了,虽然还是有点距离
使用
absolute_sigma=True
时,建议您也提供 sigma
开关,否则它们会被 1.
替换,使卡方损失函数表现为 RSS,并且如果您的不确定性不是单一的,pcov
会变得毫无意义。
提供不确定性或对其的估计,以获得有意义的
pcov
矩阵。
使用您的数据将
sigma
设置为 0.15
可显着改善 pcov
矩阵,同时保持卡方统计数据显着:
sy = np.full(y.size, 0.15)
popt, pcov = curve_fit(scattering_rate, s, y, sigma=sy, absolute_sigma=True)
np.sqrt(pcov)
# array([[3.25479068, 2.07084837, 0.45391942],
# [2.07084837, 1.35773667, 0.2563505 ],
# [0.45391942, 0.2563505 , 0.09865549]])