Python lmfit在加权拟合后将卡方面减小得太小

时间:2017-04-15 02:14:28

标签: python-2.7 curve-fitting least-squares lmfit

我正在使用lmfit使用一些测试数据和以下代码在Python 2.7中运行。我需要权重为1/y的加权拟合(使用Leven-Marq。例程)。我已经定义了权重,我在这里使用它们:

from __future__ import division
from numpy import array, var
from lmfit import Model
from lmfit.models import GaussianModel, LinearModel

import matplotlib.pyplot as plt
import seaborn as sns

xd = array([1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276,
    1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288,
     1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 1299, 1300,
     1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 1312,
     1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324,
     1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, 1333, 1334])
yd = array([238, 262, 255, 271, 270, 281, 261, 278, 280, 254, 289, 285, 304, 314,
    329, 342, 379, 450, 449, 564, 613, 705, 769, 899, 987, 1043, 1183, 1295, 1298,
    1521, 1502, 1605, 1639, 1572, 1659, 1558, 1476, 1397, 1267, 1193, 1016, 951,
    835, 741, 678, 558, 502, 480, 442, 399, 331, 334, 308, 283, 296, 265, 264, 
    273, 258, 270, 262, 263, 239, 263, 251, 246, 246, 234])

mod = GaussianModel() + LinearModel()
pars  = mod.make_params(amplitude=25300, center=1299, sigma=7, slope=0, intercept=450)
result = mod.fit(yd, pars, method='leastsq', x=xd, weights=1./yd)
rsq = 1 - result.residual.var() / var(yd)
print(result.fit_report())
print rsq

plt.plot(xd, yd,         'bo', label='raw')
plt.plot(xd, result.init_fit, 'k--', label='Initial_Guess')
plt.plot(xd, result.best_fit, 'r-', label='Best')
plt.legend()
plt.show()

输出结果为:

[[Model]]
    (Model(gaussian) + Model(linear))
[[Fit Statistics]]
    # function evals   = 27
    # data points      = 68
    # variables        = 5
    chi-square         = 0.099
    reduced chi-square = 0.002
    Akaike info crit   = -434.115
    Bayesian info crit = -423.017
[[Variables]]
    sigma:       7.57360038 +/- 0.063715 (0.84%) (init= 7)
    center:      1299.41410 +/- 0.071046 (0.01%) (init= 1299)
    amplitude:   25369.3304 +/- 263.0961 (1.04%) (init= 25300)
    slope:      -0.15015228 +/- 0.071540 (47.65%) (init= 0)
    intercept:   452.838215 +/- 93.28860 (20.60%) (init= 450)
    fwhm:        17.8344656 +/- 0.150037 (0.84%)  == '2.3548200*sigma'
    height:      1336.33919 +/- 17.28192 (1.29%)  == '0.3989423*amplitude/max(1.e-15, sigma)'
.
.
.
.
0.999999993313

最后一行(就在这里,或紧接在plt.plot(xd, yd, 'bo', label='raw')之前)是R ^ 2,结果拟合在这里。enter image description here

R ^ 2和输出的目视检查表明这是合理的拟合。我期待降低1.00(source)的卡方。但是,降低的卡方值的返回值比1.00小几个数量级。

由于lmfit中的默认值为no weights,我需要加权拟合,我已经定义了权重,但我认为我需要以不同的方式指定权重。我怀疑这种权重的规格可能导致卡方的减小变得如此之小。

是否有不同的方法来指定权重或其他一些参数,使得曲线拟合后的卡方差减小或接近1.00?

1 个答案:

答案 0 :(得分:3)

lmfit中的权重是残差在最小二乘意义上最小化的乘法因子。也就是说,它取代了

residual = model - data

residual = (model - data) * weights

一种常见的方法,也就是我认为你可能想要的一种方法,就是说权重应该是1.0 / variance_in_data,因为这通常意味着在适当的情况下减小1左右的卡方,如你链接到的优秀文章讨论。

正如那里所讨论的,问题在于确定数据的方差。对于许多情况,例如当通过计数统计来控制信号时,数据的方差可以估计为sqrt(data)。这忽略了许多噪音源,但往往是一个很好的起点。碰巧,我相信使用

result = model.fit(..., weights=np.sqrt(1.0/yd))
对于你的情况,

会导致卡顿值减小到0.8左右。我想这可能就是你想要的。

另外,澄清一个相关的观点:你链接的写入讨论当减小的卡方远离1时缩放拟合参数中的不确定性.Lmfit默认情况下在那里描述缩放(scale_covar选项可以将其关闭),以便更改权重的比例不会改变参数sigmacenter等中的不确定性的比例。不确定性的值(和,最好) -fit值)会改变一些,因为权重的变化会改变每个数据点的重点,但最佳拟合值不会发生太大变化,即使你的估计值不同,估计的不确定性应该保持相同的数量级。数据的方差(以及reduced chi-square)偏离了几个数量级。

也就是说,将脚本更改为使用weights=1.0/np.sqrt(yd)会使卡方差减小到接近1,但它不会很大程度地改变拟合变量的不确定性。