【问题标题】:lmfit minimize weighting initial datalmfit 最小化加权初始数据
【发布时间】:2018-04-16 03:02:03
【问题描述】:

我对 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”的全局变量中。然后,在绘图部分,我使用 linspace 创建了一个名为“t”的新“x”数组,然后使用“model_data”中存储的参数绘制 t 与 BMP_Gompertz(myfunction)的关系。效果很好,但看起来应该是其他更好的方法。

非常感谢您的帮助

【问题讨论】:

  • 我们怎样才能看到它从 (0, 10) 开始?我们没有您的数据集。请阅读How to create a Minimal, Complete, and Verifiable example
  • Gompertz function 究竟应该如何将点 (0, 0) 包含在 != 0 中?
  • 拟合未加权数据与拟合所有权重设置为 1 的加权数据相同。如果您不确定数据点的值,则权重通常较小,如果确定数据点的值,则权重会较大价值更大。在这里,您实际上完全确定拟合曲线必须通过数据点 [0,0] ,并且任何具有加权拟合选项的曲线拟合软件都可以做到这一点。将现有数据的所有权重设为 1.0,您将获得现有拟合,所以这样做并添加具有极大权重的点 [0,0],例如 1.0E6。
  • 我已经编辑了文本以提供我正在使用的确切数据集。感谢您的帮助
  • 我使用了我在 Gunary 方程中建议的加权拟合,并且得到了比代码中的方程更好的拟合。我使用带有拟合参数 a = 3.4870068291759794E-02,b = 2.8734350762674270E-03,c = -1.4357440419901366E 的 gunary “y = x / (a + b * x + c * pow(x, 0.5))”的数据-02

标签: python curve-fitting lmfit


【解决方案1】:

我不确定您的所有不同问题都能得到完全回答,但这里有一些 cmets:

  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等。

由于您正在进行曲线拟合并使用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)。

【讨论】:

  • 非常感谢纽维尔。
  • 答案超级有用!!!!我会尽快测试它,但看起来你解决了我所有的问题,所以再次非常感谢你!!!
猜你喜欢
  • 1970-01-01
  • 2018-03-14
  • 2021-12-19
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
  • 2014-03-26
相关资源
最近更新 更多