使用复合 PseudoVoigt 模型时出现 NameError
NameError when using composite PseudoVoigt model
在将复合 PseudoVoigt 模型与参数命名前缀结合使用时出现 NameError。
我几乎复制了上一个问题中的复合模型示例,使用的是洛伦兹剖面 (Fitting a multi-peak function to a DataSet using LMFIT)。
这对我来说很好,但洛伦兹线形不是我想要拟合的函数。
当我对单个峰使用 PseudoVoigtModel 时,我没有遇到任何问题。此外,LorentzModel 与下面的代码配合得很好(我也将其包含在代码中,因此您可以 double-check/confirm 自己)。
from lmfit.models import LorentzianModel, PseudoVoigtModel
import numpy as np
import matplotlib.pyplot as plt
def make_model_L(num):
pref = "f{0}_".format(num)
model = LorentzianModel(prefix = pref)
model.set_param_hint(pref+'amplitude', value=amplitude[num], min=0, max=5*amplitude[num])
model.set_param_hint(pref+'center', value=center[num], min=center[num]-0.5, max=center[num]+0.5)
model.set_param_hint(pref+'sigma', value=width[num], min=0, max=2)
return model
def make_model_V(num):
pref = "f{0}_".format(num)
model = PseudoVoigtModel(prefix = pref)
print('before',model.param_names)
model.set_param_hint(pref+'fraction',value = 0.7, vary = False)
model.set_param_hint(pref+'amplitude', value=amplitude[num], min=0, max=5*amplitude[num])
model.set_param_hint(pref+'center', value=center[num], min=center[num]-0.5, max=center[num]+0.5)
model.set_param_hint(pref+'fwhm', value=3, min=3/5, max=3*5)
model.set_param_hint(pref+'sigma', value=1, min=0, max=2)
model.set_param_hint(pref+'height', value=1, min=-np.inf, max=np.inf, expr='(((1-fraction)*amplitude)/(sigma*sqrt(pi/log(2)))+(fraction*amplitude)/(pi*sigma))')
print(model.param_names)
return model
# Some really coarse "data"
x = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29]
y = [1,1,1,1,3,4,5,6,5,4,3,1,1,1,1,1,1,1,1,3,4,5,6,5,4,3,1,1,1,1]
peaks_in_interval = np.array([43, 159, 191, 296, 435, 544])
amplitude = [3,3]
width = [1,1]
center = [7,21]
mod = None
for i in range(len(center)):
#this_mod = make_model_L(i)
this_mod = make_model_V(i)
if mod is None:
mod = this_mod
else:
mod = mod + this_mod
out=mod.fit(y, x=x, method='leastsq')
plt.interactive(True)
print(out.fit_report())
plt.plot(x, y)
plt.plot(x, out.best_fit, label='best fit')
plt.plot(x, out.init_fit, 'r--', label='fit with initial values')
plt.show()
我收到的错误消息:
名称错误
<_ast.Module 对象位于 0x7f562524dbe0>
^^^
名称 'fraction' 未定义
NameError: at expr='<_ast.Module object at 0x7f562524dbe0>'
我没有包含 TraceBack。它从 "out=mod.fit(y, x=x, method='leastsq')" 开始,以“~/anaconda3/lib/python3.6/site-packages/asteval/asteval.py in raise_exception(self, node, exc, msg, expr, lineno)”结束。 12=]
如前所述,使用 LorentzianModel 一切正常,我很合身(不是很好,但这是由于测试数据)。
我对 python 不是很精通,所以我无法真正就问题所在给出明智的提示。但是,我怀疑它与分数的命名以及它在 lmfit.fit() - 函数中的传递方式有关。
最好的,
一月
总是最好找到并post一个显示问题的最小示例,并且总是最好包括完整的输出,包括回溯。
例如,您会看到您遇到的问题:
from lmfit.models import PseudoVoigtModel
pref = 'f1_'
model = PseudoVoigtModel(prefix = pref)
print('before',model.param_names)
model.set_param_hint(pref+'fraction',value = 0.7, vary = False)
model.set_param_hint(pref+'amplitude', value=2, min=0, max=5)
model.set_param_hint(pref+'center', value=0, min=-0.5, max=0.5)
model.set_param_hint(pref+'fwhm', value=3, min=3/5, max=3*5)
model.set_param_hint(pref+'sigma', value=1, min=0, max=2)
# suspect line:
model.set_param_hint(pref+'height', value=1, min=-np.inf, max=np.inf,
expr='(((1-fraction)*amplitude)/(sigma*sqrt(pi/log(2)))+(fraction*amplitude)/(pi*sigma))')
print(model.param_names)
params = model.make_params()
for p in params.values():
print(p)
问题来了,因为没有一个名为fraction
的参数。正如上面几行定义的那样,它被命名为 f1_fraction
.
要解决此问题,您应该更改 pref+'height'
的表达式,以根据需要将 pref
前缀字符串包含在 fraction
、amplitude
和 sigma
.
或者:您可以删除 height
的提示,因为无论如何都会自动完成,并正确使用您提供的前缀。
另外:
a) 绝对不鼓励使用参数提示来提供初始值。提示属于模型,不应该依赖于任何特定的数据集。做一个Model一般的东西,然后给每个数据集做参数,每个数据集都有初始值。
b) 不要将边界设置得太紧或基于初始值。边界(尤其是在参数提示中)应该用于防止参数变为非物理值,例如 "it makes no sense for sigma
to be negative",而不是因为定义模型的人认为 "that ought to be close enough"。让健身发挥作用。如果您确实需要设置自定义边界,请针对每个数据集执行此操作。
在将复合 PseudoVoigt 模型与参数命名前缀结合使用时出现 NameError。
我几乎复制了上一个问题中的复合模型示例,使用的是洛伦兹剖面 (Fitting a multi-peak function to a DataSet using LMFIT)。 这对我来说很好,但洛伦兹线形不是我想要拟合的函数。
当我对单个峰使用 PseudoVoigtModel 时,我没有遇到任何问题。此外,LorentzModel 与下面的代码配合得很好(我也将其包含在代码中,因此您可以 double-check/confirm 自己)。
from lmfit.models import LorentzianModel, PseudoVoigtModel
import numpy as np
import matplotlib.pyplot as plt
def make_model_L(num):
pref = "f{0}_".format(num)
model = LorentzianModel(prefix = pref)
model.set_param_hint(pref+'amplitude', value=amplitude[num], min=0, max=5*amplitude[num])
model.set_param_hint(pref+'center', value=center[num], min=center[num]-0.5, max=center[num]+0.5)
model.set_param_hint(pref+'sigma', value=width[num], min=0, max=2)
return model
def make_model_V(num):
pref = "f{0}_".format(num)
model = PseudoVoigtModel(prefix = pref)
print('before',model.param_names)
model.set_param_hint(pref+'fraction',value = 0.7, vary = False)
model.set_param_hint(pref+'amplitude', value=amplitude[num], min=0, max=5*amplitude[num])
model.set_param_hint(pref+'center', value=center[num], min=center[num]-0.5, max=center[num]+0.5)
model.set_param_hint(pref+'fwhm', value=3, min=3/5, max=3*5)
model.set_param_hint(pref+'sigma', value=1, min=0, max=2)
model.set_param_hint(pref+'height', value=1, min=-np.inf, max=np.inf, expr='(((1-fraction)*amplitude)/(sigma*sqrt(pi/log(2)))+(fraction*amplitude)/(pi*sigma))')
print(model.param_names)
return model
# Some really coarse "data"
x = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29]
y = [1,1,1,1,3,4,5,6,5,4,3,1,1,1,1,1,1,1,1,3,4,5,6,5,4,3,1,1,1,1]
peaks_in_interval = np.array([43, 159, 191, 296, 435, 544])
amplitude = [3,3]
width = [1,1]
center = [7,21]
mod = None
for i in range(len(center)):
#this_mod = make_model_L(i)
this_mod = make_model_V(i)
if mod is None:
mod = this_mod
else:
mod = mod + this_mod
out=mod.fit(y, x=x, method='leastsq')
plt.interactive(True)
print(out.fit_report())
plt.plot(x, y)
plt.plot(x, out.best_fit, label='best fit')
plt.plot(x, out.init_fit, 'r--', label='fit with initial values')
plt.show()
我收到的错误消息:
名称错误 <_ast.Module 对象位于 0x7f562524dbe0> ^^^ 名称 'fraction' 未定义
NameError: at expr='<_ast.Module object at 0x7f562524dbe0>'
我没有包含 TraceBack。它从 "out=mod.fit(y, x=x, method='leastsq')" 开始,以“~/anaconda3/lib/python3.6/site-packages/asteval/asteval.py in raise_exception(self, node, exc, msg, expr, lineno)”结束。 12=]
如前所述,使用 LorentzianModel 一切正常,我很合身(不是很好,但这是由于测试数据)。
我对 python 不是很精通,所以我无法真正就问题所在给出明智的提示。但是,我怀疑它与分数的命名以及它在 lmfit.fit() - 函数中的传递方式有关。
最好的, 一月
总是最好找到并post一个显示问题的最小示例,并且总是最好包括完整的输出,包括回溯。
例如,您会看到您遇到的问题:
from lmfit.models import PseudoVoigtModel
pref = 'f1_'
model = PseudoVoigtModel(prefix = pref)
print('before',model.param_names)
model.set_param_hint(pref+'fraction',value = 0.7, vary = False)
model.set_param_hint(pref+'amplitude', value=2, min=0, max=5)
model.set_param_hint(pref+'center', value=0, min=-0.5, max=0.5)
model.set_param_hint(pref+'fwhm', value=3, min=3/5, max=3*5)
model.set_param_hint(pref+'sigma', value=1, min=0, max=2)
# suspect line:
model.set_param_hint(pref+'height', value=1, min=-np.inf, max=np.inf,
expr='(((1-fraction)*amplitude)/(sigma*sqrt(pi/log(2)))+(fraction*amplitude)/(pi*sigma))')
print(model.param_names)
params = model.make_params()
for p in params.values():
print(p)
问题来了,因为没有一个名为fraction
的参数。正如上面几行定义的那样,它被命名为 f1_fraction
.
要解决此问题,您应该更改 pref+'height'
的表达式,以根据需要将 pref
前缀字符串包含在 fraction
、amplitude
和 sigma
.
或者:您可以删除 height
的提示,因为无论如何都会自动完成,并正确使用您提供的前缀。
另外:
a) 绝对不鼓励使用参数提示来提供初始值。提示属于模型,不应该依赖于任何特定的数据集。做一个Model一般的东西,然后给每个数据集做参数,每个数据集都有初始值。
b) 不要将边界设置得太紧或基于初始值。边界(尤其是在参数提示中)应该用于防止参数变为非物理值,例如 "it makes no sense for sigma
to be negative",而不是因为定义模型的人认为 "that ought to be close enough"。让健身发挥作用。如果您确实需要设置自定义边界,请针对每个数据集执行此操作。