«ValueError: вход содержит значения nan» при использовании lmfit - PullRequest
0 голосов
/ 15 июня 2019

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

import matplotlib, numpy as np, matplotlib.pyplot as plt
from lmfit import Model

def pl(x, a, b, c, d):
    return (a - d) / (1+ (x / c) ** b) + d

x = [-4.522878745,
    -5.22184875,
    -5.920818754,
    -6.619788758,
    -7.318758763,
    -8.017728767,
    -8.716698771,
    -9.415668776,
    ]

y = [12,
    6,
    37,
    10297,
    22635,
    24279,
    25666,
    24365]


mod = Model(pl)
params = mod.make_params(a = 25000, b = 2, c = 1, d = 0)
result = mod.fit(y, params, x=x)
print(result.fit_report())


plt.plot(x, y, 'bo', markersize = 1.5)
plt.plot(x, result.best_fit, color = 'red', linewidth = 0.5)
plt.show()

Однако, это дает следующую ошибку:

Traceback (most recent call last):
  File "C:\Users\George\OneDrive\Subjects\EE\Regression.py", line 29, in <module>
    result = mod.fit(y, params, x=x)
  File "C:\Users\George\AppData\Local\Programs\Python\Python37\lib\site-packages\lmfit\model.py", line 1007, in fit
    output.fit(data=data, weights=weights)
  File "C:\Users\George\AppData\Local\Programs\Python\Python37\lib\site-packages\lmfit\model.py", line 1355, in fit
    _ret = self.minimize(method=self.method)
  File "C:\Users\George\AppData\Local\Programs\Python\Python37\lib\site-packages\lmfit\minimizer.py", line 1949, in minimize
    return function(**kwargs)
  File "C:\Users\George\AppData\Local\Programs\Python\Python37\lib\site-packages\lmfit\minimizer.py", line 1492, in leastsq
    lsout = scipy_leastsq(self.__residual, variables, **lskws)
  File "C:\Users\George\AppData\Local\Programs\Python\Python37\lib\site-packages\scipy\optimize\minpack.py", line 396, in leastsq
    gtol, maxfev, epsfcn, factor, diag)
  File "C:\Users\George\AppData\Local\Programs\Python\Python37\lib\site-packages\lmfit\minimizer.py", line 538, in __residual
    nan_policy=self.nan_policy)
  File "C:\Users\George\AppData\Local\Programs\Python\Python37\lib\site-packages\lmfit\minimizer.py", line 2166, in _nan_policy
    raise ValueError("The input contains nan values")
ValueError: The input contains nan values

Однако я заметил одну вещь: если я изменяю параметр c на 0, ошибка исчезает, но заменяется следующей ошибкой:

Warning (from warnings module):
  File "C:\Users\George\OneDrive\Subjects\EE\Regression.py", line 5
    return (a - d) / (1+ (x / c) ** b) + d
RuntimeWarning: divide by zero encountered in true_divide

Кроме того, 'Кривая '- это просто прямая линия:

enter image description here

Как мне решить эту проблему?

Ответы [ 2 ]

1 голос
/ 16 июня 2019

Подгонка с lmfit или scipy.optimize (или большинством других подходов к "подгонке данных") предполагает, что данные, модель наилучшего подбора и все параметры являются действительными числами. Функция вашей модели содержит (1+ (x / c) ** b), где x - отрицательное значение, c - значение, которое может быть скорректировано при подгонке, а b и c - действительные числа.

Но, конечно, negative_number**fractional_real (скажем, (-2.3)**3.4) - это комплексное число. Подходящие алгоритмы не могут справиться с ними.

Итак, вам придется решить, как обращаться с возможностями комплексных чисел. Предложение использовать (x/c)**int(b) может показаться привлекательным, но это будет означать, что подгонка не сможет найти значение b - подгонка будет вносить небольшие корректировки в каждое значение параметра, а с int(2.0) = int(2.000001) она будет определять, что небольшие изменения в b не изменяют пригонку. Тем не менее, вы можете просто запустить подгонку b с целочисленными значениями от 0 до 10 и решить, какая подгонка работает лучше.

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

from lmfit.models import StepModel, ConstantModel 

mod = StepModel(form='logistic') + ConstantModel()
params = mod.make_params(amplitude=-20000, center=-7, sigma=1, c=20000)

result = mod.fit(y, params, x=x)
print(result.fit_report())

Для ваших данных это даст наиболее подходящие значения параметров sigma ~= 0.24, center ~= -6.7, amplitude ~= -25000 и c ~= 25000 и график, который выглядит прилично.

0 голосов
/ 15 июня 2019

Кажется, что значение b изменяется каждый раз, когда ваша функция-обработчик вызывается изнутри. Значение b возрастает в точности с каждой итерацией, пока оно не станет настолько большим, что операция ** будет падать, производя nan s (внутренне это просто оценка **). В тот момент, когда он падает, значение b на моей машине равно 2.0000000298023224.

Вы можете убедиться, что b всегда является целым числом в точке вычисления:

def pl(x, a, b, c, d):
    return (a - d) / (1+ (x / c) ** int(b)) + d
...