繁体   English   中英

将两个非线性模型拟合到数据中

[英]Fitting two non-linear models to data

lmfit给出了lmfit ,我试图建立一个类似于我的问题的示例。 我的问题最初是在我的数据中我可以适应两个或三个模型,而我的模型是高度非线性的,但它对每个模型只有一个自由参数。

我的例子类似于lmfit文档:

x = np.linspace(0, 15, 301)
data = (5. * np.sin(2 * x - 0.1) * np.exp(-x*x*0.025) +(-2.6 * np.sin(-0.6 * x + 1.5) * np.exp(-x*x*3.0)+np.random.normal(size=len(x), scale=0.2) ))

def fcn2min(params, x, data):
    model=0
    for i in range(2):
        exec("amp_%d=%s"%(i+1,repr(params['amp_%d'%(i+1)].value)))
        exec("shift_%d=%s"%(i+1,repr(params['shift_%d'%(i+1)].value)))
        exec("omega_%d=%s"%(i+1,repr(params['omega_%d'%(i+1)].value)))
        exec("decay_%d=%s"%(i+1,repr(params['decay_%d'%(i+1)].value)))
        model += eval("amp_%d"%(i+1)) * np.sin(x * eval("omega_%d"%(i+1)) + eval("shift_%d"%(i+1))) * np.exp(-x*x*eval("decay_%d"%(i+1)))
    return (model-data)/data

params=Parameters()
for i in range(2):
    params.add('amp_%d'%(i+1),   value= 10,  vary=True, min=-3, max=3)
    params.add('decay_%d'%(i+1), value= 0.1,vary=True,min=0,max=4.)
    params.add('shift_%d'%(i+1), value= 0.0, vary=True,min=-np.pi, max=np.pi)
    params.add('omega_%d'%(i+1), value= 3.0, vary=True,min=-2.5, max=2.5)

result = minimize(fcn2min, params, args=(x, data),method='nelder')

获得的结果:

final = data + result.residual

# write error report
report_fit(params)
[[Variables]]
    amp_1:    -1.74789852 (init= 3)
    decay_1:   0.05493661 (init= 0.1)
    shift_1:   0.07807319 (init= 0)
    omega_1:  -2.00291964 (init= 2.5)
    amp_2:    -1.30857699 (init= 3)
    decay_2:   0.82303744 (init= 0.1)
    shift_2:  -0.04742474 (init= 0)
    omega_2:   2.44085535 (init= 2.5)
[[Correlations]] (unreported correlations are <  0.100)

自由参数看起来完全没有,但是在最终的结果图中,很明显它跟随数据的分布,但振幅不是很正确

try:
    import pylab
    pylab.plot(x, data, 'k+')
    pylab.plot(x, final, 'r')
    pylab.show()
except:
    pass

是否有任何修改代码的建议以获得正确的结果? 在此输入图像描述

好吧,我想我发现了这个问题。 我不确定这条线的用途

return (model-data)/data

但它应该是

return (model-data)

因为它是你想要最小化的。

此外,您还应该选择范围内的初始值。 修改后的代码将产生以下输出:

[[Variables]]
    amp_1:     5.23253723 (init= 10)
    decay_1:   0.02762246 (init= 0.1)
    shift_1:  -0.40774606 (init= 0)
    omega_1:   2.06744256 (init= 3)
    amp_2:     2.49467996 (init= 10)
    decay_2:   0.39205207 (init= 0.1)
    shift_2:   0.23347938 (init= 0)
    omega_2:  -0.71995187 (init= 3)
[[Correlations]] (unreported correlations are <  0.100)

情节看起来像这样:

这是整个代码:

from lmfit import minimize, Parameters, Parameter, report_fit
import numpy as np

#http://cars9.uchicago.edu/software/python/lmfit/parameters.html

# create data to be fitted

x = np.linspace(0, 15, 301)
data = (5. * np.sin(2 * x - 0.1) * np.exp(-x*x*0.025) +
(-2.6 * np.sin(-0.6 * x + 1.5) * np.exp(-x*x*3.0)+np.random.normal(size=len(x), scale=0.2) ))

def fcn2min(params, x, data):
    model=0
    for i in range(2):
        exec("amp_%d=%s"%(i+1,repr(params['amp_%d'%(i+1)].value)))
        exec("shift_%d=%s"%(i+1,repr(params['shift_%d'%(i+1)].value)))
        exec("omega_%d=%s"%(i+1,repr(params['omega_%d'%(i+1)].value)))
        exec("decay_%d=%s"%(i+1,repr(params['decay_%d'%(i+1)].value)))
        model += eval("amp_%d"%(i+1)) * np.sin(x * eval("omega_%d"%(i+1)) + eval("shift_%d"%(i+1))) * np.exp(-x*x*eval("decay_%d"%(i+1)))
    return (model-data)#/data

params=Parameters()
for i in range(2):
    params.add('amp_%d'%(i+1),   value= 10,  vary=True, min=0, max=13)
    params.add('decay_%d'%(i+1), value= 0.1,vary=True,min=0,max=1.4)
    params.add('shift_%d'%(i+1), value= 0.0, vary=True,min=-np.pi, max=np.pi)
    params.add('omega_%d'%(i+1), value= 3.0, vary=True,min=-3.5, max=3.5)

result = minimize(fcn2min, params, args=(x, data),method='nelder')

final = data + result.residual
report_fit(params)
try:
    import pylab
    pylab.plot(x, data, 'k+')
    pylab.plot(x, final, 'r')
    pylab.show()
except:
    pass

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM