lmfit最小化加权初始数据

时间:2018-04-15 09:58:41

标签: python curve-fitting lmfit

我是python的新手,我正在尝试使用lmfit做一些曲线拟合。代码工作得很好,但我想强制通过原点(0,0)。我在stakoverlow看到过使用" curve_fit"你可以添加和归属" sigma"这样可以解决这个问题,但这并不适用于"最小化"。你对此有什么解决方法吗?

到目前为止,这是我的代码:

##############################################################################
###################### IMPORT MODULES ########################################
##############################################################################
import numpy as np
import matplotlib.pyplot as plt
from lmfit import minimize, Parameters
from lmfit import report_fit

##############################################################################
##################### DATA ##################################
##############################################################################
x=np.array([0,1, 4, 6, 8, 9, 11, 13, 15, 18, 20, 27])
data=np.array([0, 67, 208, 339, 460, 539, 599, 635, 659, 685, 701, 731])

##############################################################################
######################## GOMPERTZ FUNCTION DEFINITION#########################
##############################################################################

def BMP_Gompertz(params, x, data):
    BMPmax=params['BMPmax'].value
    Rmax=params['Rmax'].value
    Lambda=params['Lambda'].value

    model=BMPmax*np.exp(-np.exp(Rmax*np.exp(1)/BMPmax*(Lambda-x)+1))

    global model_data
    model_data=[BMPmax,Rmax,Lambda]

    return data-model

params=Parameters()
params.add('BMPmax', value=300., min=0.)
params.add('Rmax', value=25., min=0.) 
params.add('Lambda',value=0.5, min=0.)

model_data=[]


##############################################################################
###################### GOMPERTZ CURVE FITTING & REPORT #######################
##############################################################################
result=minimize(BMP_Gompertz, params, args=(x,data))
report_fit(result.params)

##############################################################################
########################## GOMPERTZ PLOTTING #################################
##############################################################################
plt.plot(x, data, 'bo')
t=np.linspace(0.,100,10000)
plt.plot(t,model_data[0]*np.exp(-np.exp(model_data[1]*np.exp(1)/model_data[0]*(model_data[2]-t)+1)))
plt.xlabel('Days')
plt.ylabel('BMP (NLbiogas/kg SV)')
plt.show()

你可以看到,拟合不是从(0,0)开始,而是在(0,10)左右,我想总是强迫它从(0,0)开始...看起来像我我仍然无法上传图片(还没有暂停)...无论如何,我认为你可以明白这一点。

还有另外一个问题,是否存在另一种存储参数和绘制结果的方法?现在通过将它们存储在名为" model_data"的全局变量中来存储模型返回的参数。然后,在情节部分,我创建了一个新的" x"数组称为" t"使用linspace,然后使用存储在" model_data"中的参数绘制t vs BMP_Gompertz(myfunction)。效果很好,但它看起来应该是其他更好的方法。

非常感谢您的帮助

1 个答案:

答案 0 :(得分:1)

我不确定您的所有不同问题都可以得到完全解答,但这里有一些评论:

  1. 您可以为合身添加重量。使用minimize的示例,您可以传入包含数据不确定性的数组sigma,并将return data-model更改为return (data-model)/sigma。下面,我将建议使用lmfit.Model,其指定权重的方式略有不同。

  2. 即使使用加权,让您当前的模型通过(0,0)也具有挑战性。也就是说,指数函数衰减,但不会达到0,因此您可能需要确定什么是"足够零"。如果这是物理要求,您可能需要修改模型。

  3. 存储拟合结果,您无需使用model_data。返回的result.params包含最适合的参数,您可以获得result.params['Rmax'].value等。

  4. 由于您正在进行曲线拟合并使用lmfit,我建议使用lmfit.Model,这将简化您的代码并更容易提取预测的绘图模型。使用lmfit.Model您在目标函数中完成的大部分工作都是为您完成的,您的脚本将成为:

    import numpy as np
    import matplotlib.pyplot as plt
    from lmfit import Model
    
    x=np.array([0,1, 4, 6, 8, 9, 11, 13, 15, 18, 20, 27])
    data=np.array([0, 67, 208, 339, 460, 539, 599, 635, 659, 685, 701, 731])
    
    # This function now returns the model. The function arguments are 
    # named so that Model() will know what to name the Parameters.
    def BMP_Gompertz(x, bmpmax, rmax, xlambda):
        return bmpmax *np.exp(-np.exp((rmax*np.exp(1)/bmpmax)*(xlambda-x)+1))
    
    # create a Model from the model function
    bmodel = Model(BMP_Gompertz)
    
    # create Parameters, giving initial values
    params = bmodel.make_params(bmpmax=300, rmax=25, xlambda=0.5)
    params['bmpmax'].min = 0
    params['rmax'].min = 0
    params['xlambda'].min = 0
    
    # do fit, print result
    result = bmodel.fit(data, params, x=x)
    print(result.fit_report())
    
    # plot results -- note that `best_fit` is already available
    plt.plot(x, data, 'bo')
    plt.plot(x, result.best_fit, 'r--')
    
    t=np.linspace(0.,100,10000)
    
    # use `result.eval()` to evaluate model given params and x
    plt.plot(t, bmodel.eval(result.params, x=t), 'k-')
    plt.xlabel('Days')
    plt.ylabel('BMP (NLbiogas/kg SV)')
    plt.show()
    

    要为模型拟合添加权重,您可以定义要用于乘以 data-model的权重数组,并将其传递给Model.fit。要强调具有最低值的数据(因此将拟合推向(0,0),您可能会使用以下内容:

    weights = 1.0 / np.sqrt(data + 1)
    result = bmodel.fit(data, params, x=x, weights=weights)
    

    同样,这将强调较小的y值,并倾向于在x=0处下推模型值,但不会真正强制结果为(0,0)。