简体   繁体   English

将Python lmfit与函数中可变数量的参数一起使用

[英]Use Python lmfit with a variable number of parameters in function

I am trying to deconvolve complex gas chromatogram signals into individual gaussian signals. 我正在尝试将复杂的气相色谱信号解卷积为单个高斯信号。 Here is an example, where the dotted line represents the signal I am trying to deconvolve. 这是一个示例,其中虚线表示我要解卷积的信号。

在此处输入图片说明 I was able to write the code to do this using scipy.optimize.curve_fit; 我能够使用scipy.optimize.curve_fit编写代码来执行此操作; however, once applied to real data the results were unreliable. 但是,一旦应用于实际数据,结果将不可靠。 I believe being able to set bounds to my parameters will improve my results, so I am attempting to use lmfit, which allows this. 我相信能够为我的参数设置界限会改善我的结果,因此我尝试使用lmfit来实现这一点。 I am having a problem getting lmfit to work with a variable number of parameters. 我在使lmfit与可变数量的参数一起使用时遇到问题。 The signals I am working with may have an arbitrary number of underlying gaussian components, so the number of parameters I need will vary. 我正在使用的信号可能具有任意数量的基础高斯分量,因此我需要的参数数量会有所不同。 I found some hints here, but still can't figure it out... 我在这里找到了一些提示,但仍然无法解决...

Creating a python lmfit Model with arbitrary number of parameters 使用任意数量的参数创建python lmfit模型

Here is the code I am currently working with. 这是我当前正在使用的代码。 The code will run, but the parameter estimates do not change when the model is fit. 该代码将运行,但是在拟合模型时参数估计不会更改。 Does anyone know how I can get my model to work? 有谁知道我如何使我的模型工作?

import numpy as np
from collections import OrderedDict
from scipy.stats import norm
from lmfit import Parameters, Model

def add_peaks(x_range, *pars):
    y = np.zeros(len(x_range))
    for i in np.arange(0, len(pars), 3):
        curve = norm.pdf(x_range, pars[i], pars[i+1]) * pars[i+2]
        y = y + curve
    return(y)

# generate some fake data
x_range = np.linspace(0, 100, 1000)
peaks = [50., 40., 60.]
a = norm.pdf(x_range, peaks[0], 5) * 2
b = norm.pdf(x_range, peaks[1], 1) * 0.1
c = norm.pdf(x_range, peaks[2], 1) * 0.1
fake = a + b + c

param_dict = OrderedDict()

for i in range(0, len(peaks)):
    param_dict['pk' + str(i)] = peaks[i]
    param_dict['wid' + str(i)] = 1.
    param_dict['mult' + str(i)] = 1.

# In case, you'd like to see the plot of fake data
#y = add_peaks(x_range, *param_dict.values())
#plt.plot(x_range, y)
#plt.show()

# Initialize the model and fit
pmodel = Model(add_peaks)

params = pmodel.make_params()
for i in param_dict.keys():
    params.add(i, value=param_dict[i])

result = pmodel.fit(fake, params=params, x_range=x_range)
print(result.fit_report())

I was able to find a solution here: 我可以在这里找到解决方案:

https://lmfit.github.io/lmfit-py/builtin_models.html#example-3-fitting-multiple-peaks-and-using-prefixes https://lmfit.github.io/lmfit-py/builtin_models.html#example-3-fitting-multiple-peaks-and-using-prefixes

Building on the code above, the following accomplishes what I was trying to do... 在上面的代码的基础上,以下代码完成了我试图做的事情...

from lmfit.models import GaussianModel

gauss1 = GaussianModel(prefix='g1_')
gauss2 = GaussianModel(prefix='g2_')
gauss3 = GaussianModel(prefix='g3_')
gauss4 = GaussianModel(prefix='g4_')
gauss5 = GaussianModel(prefix='g5_')

gauss = [gauss1, gauss2, gauss3, gauss4, gauss5]
prefixes = ['g1_', 'g2_', 'g3_', 'g4_', 'g5_']

mod = np.sum(gauss[0:len(peaks)])
pars = mod.make_params()

for i, prefix in zip(range(0, len(peaks)), prefixes[0:len(peaks)]):
    pars[prefix + 'center'].set(peaks[i])

init = mod.eval(pars, x=x_range)
out = mod.fit(fake, pars, x=x_range)
print(out.fit_report(min_correl=0.5))
out.plot_fit()
plt.show()

在此处输入图片说明

I think you would be better off using lmfit s ability to build composite model. 我认为使用lmfit的功能来构建复合模型会更好。
That is, with a single peak defined with 也就是说,用

from scipy.stats import norm
def peak(x, amp, center, sigma):
    return amp * norm.pdf(x, center, sigma)

(see also lmfit.models.GaussianModel ), you can build a model with many peaks: (另请参见lmfit.models.GaussianModel ),您可以构建具有许多峰的模型:

npeaks = 3
model = Model(peak, prefix='p1_')
for i in range(1, npeaks):
     model = model + Model(peak, prefix='p%d_' % (i+1))

params = model.make_params()

Now model will be a sum of 3 Gaussian functions, and the params created for that model will have names like p1_amp , p1_center , p2_amp , ..., which you can add sensible initial values and/or bounds and/or constraints. 现在, model将是3个高斯函数的总和,并且为该模型创建的params将具有p1_ampp1_centerp2_amp ,...之类的名称,您可以添加合理的初始值和/或范围和/或约束。

Given your example data, you could pass in initial values to make_params like 给定示例数据,您可以将初始值传递给make_params例如

params = model.make_params(p1_amp=2.0, p1_center=50., p1_sigma=2, 
                           p2_amp=0.2, p2_center=40., p2_sigma=2, 
                           p3_amp=0.2, p3_center=60., p3_sigma=2)

result = model.fit(fake, params, x=x_range)

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

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