NameError при использовании составной модели PseudoVoigt - PullRequest
1 голос
/ 05 апреля 2019

Я получаю NameError при использовании составной модели PseudoVoigt в сочетании с префиксами для именования параметров.

Я в значительной степени скопировал пример для составной модели из предыдущего вопроса, используя профиль Лоренца ( Подгонка многопиковой функции к DataSet с использованием LMFIT ). Это прекрасно работает для меня, но форма линии Лоренца - это не та функция, которую я хочу соответствовать.

Когда я использую PseudoVoigtModel для одного пика, у меня нет проблем. Кроме того, LorentzModel отлично работает с приведенным ниже кодом (я также включил его в код, чтобы вы могли дважды проверить / подтвердить себя).

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()

Я получаю сообщение об ошибке:

NameError <_ast.Module объект в 0x7f562524dbe0> ^^^ имя «фракция» не определено

NameError: at expr = '<_ ast.Module объект в 0x7f562524dbe0>'

Я не включил TraceBack. Он начинается в "out = mod.fit (y, x = x, method = 'leastsq')" и заканчивается в "~ / anaconda3 / lib / python3.6 / site-packages / asteval / asteval.py в подъеме_ исключение (self , node, exc, msg, expr, lineno) "

Как упоминалось ранее, с LorentzianModel все работает нормально, я подхожу (не очень, но это из-за тестовых данных).

Я не очень хорошо разбираюсь в python, поэтому я не могу дать действительно информированные подсказки о том, в чем может быть проблема. Однако я подозреваю, что это связано с именованием дроби и с тем, как оно передается в функцию lmfit.fit ().

Лучший, Jan

1 Ответ

0 голосов
/ 05 апреля 2019

Всегда лучше найти и опубликовать минимальный пример, который показывает проблему, и всегда лучше включить полный вывод, включая трассировку.

Например, вы увидите проблему, с которой вы столкнулись:

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) Использование подсказок параметров для предоставления начальных значений, как и вы, определенно не рекомендуется. Подсказки принадлежат модели и не должны зависеть от какого-либо конкретного набора данных. Создайте модель как общую вещь, а затем создайте параметры с начальными значениями для каждого набора данных.

b) не устанавливайте слишком жесткие границы или не используйте начальные значения. Границы (особенно в подсказках параметров) следует использовать для предотвращения перехода параметра к нефизическим значениям, таким как «нет смысла считать sigma отрицательным», а не потому, что человек, определяющий модель, думает «это должно быть достаточно близко". Пусть подгонка сделает свое дело. Если вам нужно установить собственные границы, сделайте это для каждого набора данных.

...