我有很多x-y数据点,y需要适应非线性函数。在某些情况下,这些函数可以是线性的,但更通常是指数衰减,高斯曲线等。 SciPy支持scipy.optimize.curve_fit
这种拟合,我也可以指定每个点的权重。这给了我加权的非线性拟合,这很好。从结果中,我可以提取参数及其各自的错误。
只有一点需要注意:错误仅用作权重,但未包含在错误中。如果我将所有数据点的误差加倍,我预计结果的不确定性也会增加。所以我构建了一个测试用例(source code)来测试它。
适合scipy.optimize.curve_fit
给我:
Parameters: [ 1.99900756 2.99695535]
Errors: [ 0.00424833 0.00943236]
但与2 * y_err
:
Parameters: [ 1.99900756 2.99695535]
Errors: [ 0.00424833 0.00943236]
相同但有2 * y_err:
所以你可以看到值是相同的。这告诉我算法没有考虑到这些,但我认为值应该是不同的。
我也在这里阅读了另一种合适的方法,所以我也尝试使用scipy.odr
:
Beta: [ 2.00538124 2.95000413]
Beta Std Error: [ 0.00652719 0.03870884]
但与20 * y_err
:
Beta: [ 2.00517894 2.9489472 ]
Beta Std Error: [ 0.00642428 0.03647149]
值略有不同,但我认为这可以解释错误的增加。我认为这只是围绕错误或有点不同的权重。
是否有一些软件包允许我调整数据并获得实际错误?我在书中有公式,但如果我不需要,我不想自己实现。
我现在在另一个问题中阅读了linfit.py
。这很好地处理了我的想法。它支持两种模式,第一种是我需要的。
Fit with linfit:
Parameters: [ 2.02600849 2.91759066]
Errors: [ 0.00772283 0.04449971]
Same but with 20 * y_err:
Parameters: [ 2.02600849 2.91759066]
Errors: [ 0.15445662 0.88999413]
Fit with linfit(relsigma=True):
Parameters: [ 2.02600849 2.91759066]
Errors: [ 0.00622595 0.03587451]
Same but with 20 * y_err:
Parameters: [ 2.02600849 2.91759066]
Errors: [ 0.00622595 0.03587451]
我应该回答我的问题,还是现在关闭/删除它?
答案 0 :(得分:4)
请注意,请参阅curvefit
的文档:
sigma:无或N长度序列 如果不是None,则此向量将用作相对权重 最小二乘问题。
此处的关键点是作为相对权重,因此,第53行中的yerr
和第57行中的2*yerr
应该为您提供相似的结果(如果不是相同的话)。
当您增加实际残留错误时,您会看到协方差矩阵中的值变大。如果我们将y += random
更改为y += 5*random
中的generate_data()
:
Fit with scipy.optimize.curve_fit:
('Parameters:', array([ 1.92810458, 3.97843448]))
('Errors: ', array([ 0.09617346, 0.64127574]))
与原始结果相比:
Fit with scipy.optimize.curve_fit:
('Parameters:', array([ 2.00760386, 2.97817514]))
('Errors: ', array([ 0.00782591, 0.02983339]))
另请注意,参数估计值现在远离(2,3)
,正如我们预期的那样,残差误差增加,参数估计值的置信区间更大。
答案 1 :(得分:3)
一种运行良好且实际上提供更好结果的方法是bootstrap方法。当给出有错误的数据点时,使用参数自举,并让每个x
和y
值描述高斯分布。然后,我们将从每个分布中绘制一个点,并获得一个新的自举样本。执行简单的未加权拟合可为参数提供一个值。
这个过程重复大约300到几千次。最终将得到拟合参数的分布,其中可以采用均值和标准差来获得值和误差。
另一个巧妙的事情是,结果并没有获得单一的拟合曲线,而是很多。对于每个插值x
值,可以再次获取多个值f(x, param)
的均值和标准差,并获得错误带:
答案 2 :(得分:1)
简短回答
对于包含y的不确定性的绝对值(和odr情况下的x):
scipy.odr
案例中使用stddev = numpy.sqrt(numpy.diag(cov))
其中cov是输出中odr给出的协方差矩阵。scipy.optimize.curve_fit
案例中使用absolute_sigma=True
对于相对值(不包括不确定性):
在scipy.odr
案例中,使用输出中的sd值。
在scipy.optimize.curve_fit案例中使用absolute_sigma=False
标记。
像这样使用numpy.polyfit:
p, cov = numpy.polyfit(x, y, 1,cov = True)
errorbars = numpy.sqrt(numpy.diag(cov))
答案很长
所有功能中都有一些未记录的行为。我的猜测是混合相对值和绝对值的函数。最后,这个答案是代码,根据你处理输出的方式给出你想要的东西(或者没有)(有一个bug?)。此外,curve_fit可能已经获得了'absolute_sigma'最近举旗?
我的观点是在输出中。似乎odr
计算标准差,因为没有不确定性,类似于polyfit,但如果标准偏差是根据协方差矩阵计算的,则存在不确定性。 curve_fit使用absolute_sigma=True
标志执行此操作。以下是包含
odr: 1.739631e-06 0.02302262 [ 0.00014863 0.0170987 ] [ 0.00131895 0.15173207]
curve_fit: 2.209469e-08 0.00029239 [ 0.00014864 0.01709943] [ 0.0004899 0.05635713]
polyfit: 2.232016e-08 0.00029537 [ 0.0001494 0.01718643]
请注意,odr和polyfit具有完全相同的标准偏差。 Polyfit 不将不确定性作为输入,因此 odr在计算标准差时不会使用不确定性。协方差矩阵使用它们,如果在情况下,则根据协方差矩阵计算标准差,并且如果不确定性增加则它们会发生变化。在下面的代码中摆弄dy
将显示它。
我在这里写这篇文章主要是因为知道何时找出错误限制很重要(而且scipy所指的fortran odrpack指南有一些误导性的信息:标准差应该是协方差矩阵的平方根,如指南所说但它不是)。
import scipy.odr
import scipy.optimize
import numpy
x = numpy.arange(200)
y = x + 0.4*numpy.random.random(x.shape)
dy = 0.4
def stddev(cov): return numpy.sqrt(numpy.diag(cov))
def f(B, x): return B[0]*x + B[1]
linear = scipy.odr.Model(f)
mydata = scipy.odr.RealData(x, y, sy = dy)
myodr = scipy.odr.ODR(mydata, linear, beta0 = [1.0, 1.0], sstol = 1e-20, job=00000)
myoutput = myodr.run()
cov = myoutput.cov_beta
sd = myoutput.sd_beta
p = myoutput.beta
print 'odr: ', cov[0,0], cov[1,1], sd, stddev(cov)
p2, cov2 = scipy.optimize.curve_fit(lambda x, a, b:a*x+b,
x, y, [1,1],
sigma = dy,
absolute_sigma = False,
xtol = 1e-20)
p3, cov3 = scipy.optimize.curve_fit(lambda x, a, b:a*x+b,
x, y, [1,1],
sigma = dy,
absolute_sigma = True,
xtol = 1e-20)
print 'curve_fit: ', cov2[0,0], cov2[1,1], stddev(cov2), stddev(cov3)
p, cov4 = numpy.polyfit(x, y, 1,cov = True)
print 'polyfit: ', cov4[0,0], cov4[1,1], stddev(cov4)