Как исправить «Массив, возвращаемый функцией, изменил размер между вызовами» при использовании lmfit для минимизации? - PullRequest
1 голос
/ 10 июля 2019

Как я могу исправить код с ошибкой «Массив, возвращаемый функцией, изменил размер между вызовами» при использовании lmfit для минимизации?

Пожалуйста, найдите мой код ниже:

import numpy as np
import pandas as pd
import lmfit as lf

#model needs to be fitted
x0 = 75
def func(params, x, Tsky):
    A = params['amp']
    w = params['width']
    t = params['thickness']
    v0 = params['mid_freq']
    b0 = params['b0']
    b1 = params['b1']
    b2 = params['b2']
    b3 = params['b3']
    b4 = params['b4']
    B = (4 * (x - v0)**2. / w**2.) * np.log(-1./t * np.log((1 + np.exp(-t))/2))
    T21 = -A * (1 - np.exp(-t * np.exp(B)))/(1 - np.exp(-t))
    model = T21 + b0 * ((x/x0)**(-2.5 + b1 + b2 * np.log(x/x0))) * np.exp(-b3*(x/x0)**-2.) + b4 *  (x/x0)**-2.
    return (Tsky-model)

#read the data
df = pd.read_csv('figure1_plotdata.csv')
data_list = df.T.values.tolist()
xdata = np.array(data_list[0])
Tsky = np.array(data_list[2])

#initial value of the parameters
params = lf.Parameters()
params.add('amp', value=0.2)
params.add('width', value=10)
params.add('thickness', value=5)
params.add('mid_freq', value=70)
params.add('b0', value=500)
params.add('b1', value=-0.5)
params.add('b2', value=-0.5)
params.add('b3', value=-0.5)
params.add('b4', value=500)

#minimize the function
out = lf.minimize(func, params, args=(xdata, Tsky), method='leastsq', kws=None, iter_cb=None, scale_covar=True, nan_policy='omit', calc_covar=True)

print(lf.fit_report(out))

Вот сообщение об ошибке:

File "/home/ankita/Dropbox/Python/Bowman_work/min.py", line 81, in <module>
    out = lf.minimize(func, params, args=(xdata, Tsky), method='leastsq', kws=None, iter_cb=None, scale_covar=True, nan_policy='omit', calc_covar=True)

  File "/home/ankita/anaconda3/lib/python3.7/site-packages/lmfit-0.9.13-py3.7.egg/lmfit/minimizer.py", line 2300, in minimize
    return fitter.minimize(method=method)

  File "/home/ankita/anaconda3/lib/python3.7/site-packages/lmfit-0.9.13-py3.7.egg/lmfit/minimizer.py", line 1949, in minimize
    return function(**kwargs)

  File "/home/ankita/anaconda3/lib/python3.7/site-packages/lmfit-0.9.13-py3.7.egg/lmfit/minimizer.py", line 1492, in leastsq
    lsout = scipy_leastsq(self.__residual, variables, **lskws)

  File "/home/ankita/anaconda3/lib/python3.7/site-packages/scipy/optimize/minpack.py", line 394, in leastsq
    gtol, maxfev, epsfcn, factor, diag)

**ValueError: The array returned by a function changed size between calls**

1 Ответ

0 голосов
/ 10 июля 2019

Если бы вы использовали

out = lf.minimize(func, params,...,nan_policy='raise')

, вы бы увидели возникшее исключение, сообщающее, что существуют NaN.Когда вы используете nan_policy='omit', любые такие NaN, которые генерируются вашей моделью, удаляются из остаточного массива, и поэтому размер массива изменяется между вызовами.Фитинг не может обрабатывать NaN или изменения размера массивов - вы должны устранить их.

В частности, np.log(x) - это NaN, когда x<0.У вас есть np.log() со сложным аргументом, который зависит от значения параметра t.Если этот аргумент опускается ниже 0 для некоторого значения t, модель имеет NaN и не имеет смысла.Вам нужно убедиться, что этот аргумент не может быть меньше 0. Возможно, достаточно использовать

params.add('thickness', value=5, min=0)

.Но вы должны изучить вашу модель более подробно и определить, имеет ли это смысл.

Ваша модель выглядит довольно сложной для меня.Я не могу догадаться, откуда такая модель.Взятие нескольких np.exp() и np.log() является своего рода запросом на числовую нестабильность.Итак, я не знаю, что простое принуждение t к положительному результату даст хорошую пригонку, но оно может указать вам правильное направление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...