lmfit: превышена максимальная глубина рекурсии

Я использую lmfit, чтобы подогнать «сложную» модель к экспериментальным данным.

Я определяю параметры модели следующим образом:

def model(t, y0, h, A1, x1, s1, A2, x2, s2, A3, x3, s3, A4, x4, s4):

        y = y0 + h * (
                      A1 * (0.5 + 0.5 * erf((t - x1) / (s1 * 2**0.5))) +
                      A2 * (0.5 + 0.5 * erf((t - x2) / (s2 * 2**0.5))) +
                      A3 * (0.5 + 0.5 * erf((t - x3) / (s3 * 2**0.5))) +
                      A4 * (0.5 + 0.5 * erf((t - x4) / (s4 * 2**0.5)))
                      )
        return y


mod = Model(model)

# sys.setrecursionlimit(150000)

# Set the parameters, define their bounds and their relations
mod.set_param_hint('y0', value=self.spin_y0.value())
mod.set_param_hint('h', value=self.spin_h.value())

mod.set_param_hint('A1', value=self.spin_A1.value(), min=0, max=1),
mod.set_param_hint('x1', value=self.spin_x1.value(), min=0, max=self.x[-1])
mod.set_param_hint('s1', value=self.spin_s1.value(), min=0)

mod.set_param_hint('A2', value=self.spin_A2.value(), min=0, max=1),
mod.set_param_hint('x2', value=self.spin_x2.value(), min=0, max=self.x[-1])
mod.set_param_hint('s2', value=self.spin_s2.value(), min=0)

mod.set_param_hint('A3', value=self.spin_A3.value(), min=0, max=1),
mod.set_param_hint('x3', value=self.spin_x3.value(), min=0, max=self.x[-1])
mod.set_param_hint('s3', value=self.spin_s3.value(), min=0)

mod.set_param_hint('A4', value=self.spin_A4.value(), min=0, max=1),
mod.set_param_hint('x4', value=self.spin_x4.value(), min=0, max=self.x[-1])
mod.set_param_hint('s4', value=self.spin_s4.value(), min=0)

mod.set_param_hint('A1', expr='1-A2-A3-A4')
mod.set_param_hint('A2', expr='1-A1-A3-A4')
mod.set_param_hint('A3', expr='1-A1-A2-A4')
mod.set_param_hint('A4', expr='1-A1-A2-A3')

mod.make_params()

# Fit the data !
result = mod.fit(self.y, t=self.x)

Я использую spinBox для получения значений, которые будут использоваться в качестве начальных значений (моя программа представляет собой графический интерфейс).

У меня проблема с A1, A2, A3 и A4. Они зависимы, и их сумма должна быть равна 1.

если я прокомментирую

mod.set_param_hint('A1', expr='1-A2-A3-A4')
mod.set_param_hint('A2', expr='1-A1-A3-A4')
mod.set_param_hint('A3', expr='1-A1-A2-A4')
mod.set_param_hint('A4', expr='1-A1-A2-A3

Параметры варьируются от 0 до 1 (я определяю этот диапазон при определении параметров), но их сумма никогда не равна 1.

Когда эти строки не комментируются, у меня есть следующее исключение:

File "/usr/lib/python3.4/site-packages/lmfit/minimizer.py", line 255, in __update_paramval
    self.__update_paramval(dep)
  File "/usr/lib/python3.4/site-packages/lmfit/minimizer.py", line 250, in __update_paramval
    if getattr(par, 'expr', None) is not None:
RuntimeError: maximum recursion depth exceeded

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

Вы хоть представляете, в чем проблема?


person JPFrancoia    schedule 20.03.2015    source источник
comment
Если ваша программа сильно зависит от рекурсии, вы, вероятно, попадете в нее, несмотря ни на что. Попробуйте переконфигурировать его в цикл, если это возможно, или переключитесь на язык, который поддерживает оптимизацию хвостового вызова.   -  person Carcigenicate    schedule 20.03.2015


Ответы (1)


Хорошо, для будущего меня и других людей, ищущих решение, я нашел его. Я использовал scimin.fmin_slsqp для выполнения этой работы. Вот пример кода:

def model(t, params):

    y0, h, A1, x1, s1, A2, x2, s2, A3, x3, s3, A4, x4, s4 = [value for value in params]

    y = y0 + h * (
                  A1 * (0.5 + 0.5 * erf((t - x1) / (s1 * 2**0.5))) +
                  A2 * (0.5 + 0.5 * erf((t - x2) / (s2 * 2**0.5))) +
                  A3 * (0.5 + 0.5 * erf((t - x3) / (s3 * 2**0.5))) +
                  A4 * (0.5 + 0.5 * erf((t - x4) / (s4 * 2**0.5)))
                 )

    return y


def sum_residuals(params):  # the function we want to minimize

    y0, h, A1, x1, s1, A2, x2, s2, A3, x3, s3, A4, x4, s4 = [value for value in params]

    return sum((list_y - model(list_x, params))**2)


def constraints(params):

    y0, h, A1, x1, s1, A2, x2, s2, A3, x3, s3, A4, x4, s4 = [value for value in params]

    return 1 - (A1 + A2 + A3 + A4)


pfit = scimin.fmin_slsqp(sum_residuals,
                         p0,
                         f_eqcons=constraints,
                         bounds=bounds,
                         iprint=0,
                         iter=300
                        )

Где p0 — последовательность начальных параметров. Однако fmin_slqp не возвращает ковариационную матрицу, и я не смог рассчитать доверительные интервалы для подобранных параметров. Для этого я использовал метод начальной загрузки.

person JPFrancoia    schedule 29.03.2015