Примечание: обновлено, чтобы отразить тот факт, что компоненты вашей модели используют разные независимые переменные (age
, inc
, ...).
Часть того, что вы спрашиваете о том, как гибко создаватьподбор моделей с некоторыми вариациями того, какие функции используются для построения модели.Я рекомендую создавать функции компонентной модели с осмысленными именами аргументов, возможно (извините, если они неполные или не совсем соответствуют вашим определениям - цель состоит в том, чтобы проиллюстрировать подход):
import numpy as np
from lmfit import Model
from lmfit.models import ConstantModel
## Base models, depending on independent variable 'inc'
def double_break(inc, offset, amp, breakpoint, maxval=3, age=None):
return np.minimum(maxval, offset+amp*np.maximum(inc - breakpoint, 0))
def double_asymptote(inc, offset, amp, decay_off, decay_slope, age=None):
return offset + amp/(1.0+np.exp(decay_off+decay_slope*inc))
def constant(inc, c, age=None):
return c
## Seasoning models, depending on independent variable 'age'
def hockey_stick(age, offset, slope, maxval=1, inc=None):
return np.minimum(offset + slope/age, maxval)
def quadratic(age, offset, slope, quad, inc=None):
return (offset + slope*age * quad*age*age)
def exponential_au(age, amp, decay1, decay2, inc=None):
return amp*(1+np.exp(-decay1*age) - np.exp(-decay2*age))
каждый из этихфункции могут быть превращены в lmfit.Model
, которые будут иметь имена параметров, которые являются более значимыми, чем s1
, и т. д. и могут запускаться индивидуально для тестирования.С этими определениями вы могли бы иметь функцию build_model()
, которая могла бы выглядеть как
def build_model(base='double_break', seasoning='hockey_stick'):
if base == 'double_break':
basemodel = Model(double_break, prefix='base_', independent_vars=['inc', 'age'])
elif base == 'double_asymptote':
basemodel = Model(double_asymptote, prefix='base_', independent_vars=['inc', 'age'])
else:
basemodel = Model(constant, prefix='base_', independent_vars=['inc', 'age'])
if seasoning == 'hockey_stick':
smodel = Model(hockey_stick, prefix='seasoning_', independent_vars=['inc', 'age'])
elif seasoning == 'quadratic':
smodel = Model(quadratic, prefix='seasoning_', independent_vars=['inc', 'age'])
else:
smodel = Model(exponential_au, prefix='seasoning_', independent_vars=['inc', 'age'])
return basemodel*smodel
Модель, которую построит эта функция, будет составной моделью (основа * приправа), а параметры будут сделаны с помощью
model = build_model(base='double_break', seasoning='quadratic')
params = model.make_params(base_offset=1, base_amp=2,base_breakpoint=1000,
seasoning_offset=1, seasoning_slope=0.02, seasoning_quad=0)
будет иметь более значимые имена, такие как base_offset
, seasoning_offset
, seasoning_slope
и т. Д. Чтобы использовать эту модель, вы можете сделать
inc = np.linspace(-1, 1, 11)
age = np.linspace(5, 10, 11)
test = model.eval(params, age=age, inc=inc)
result = model.fit(ydata, params, age=age, inc=inc)
Было бы довольно легко добавитьновые функции для «основы» или «приправы», или для добавления другого компонента в модель.
В этой модели есть одна вещь, которая может не соответствовать вашему сценарию использования, в зависимости от того, что вы подразумеваете под"\ CDOT".То есть эти компоненты модели просто умножаются и поэтому независимые переменные должны иметь одинаковую длину.Если у вас есть 1000 inc
значений и 10 age
значений, неясно, как вы хотите умножить эти две функции.Если вам нужно сделать какой-либо другой продукт или комбинацию моделей компонентов, отличную от базового сложения, вычитания, умножения или деления, вы можете сделать это, но это потребует дополнительных шагов для предоставления функции оператора, используемой для объединения моделей компонентов.За подробностями обращайтесь к документации lmfit (с примером выполнения свертки).