TypeError: Неверный ввод: N=5 не должно превышать M=2

Я пытаюсь использовать scipy.optimize.curve_fit с настраиваемой функцией подгонки (примерно следуя этот учебник):

# Fit function
def fit_function(x, y, x0, y0, A, FWHM):
    return A*np.exp(1)*4*np.log(2)*((x+x0)**2 + (y+y0)**2)/FWHM**2*np.exp(-4*np.log(2)*((x+x0)**2 + (y+y0)**2)/FWHM**2)

# Open image file
img = Image.open('/home/user/image.tif')

# xdata
X, Y = img.size
xRange = np.arange(1, X+1)
yRange = np.arange(1, Y+1)
xGrid, yGrid = np.meshgrid(xRange, yRange)
xyGrid = np.vstack((xGrid.ravel(), yGrid.ravel()))

# ydata
imgArray = np.array(img)
imgArrayFlat = imgArray.ravel()

# Fitting
params_opt, params_cov = curve_fit(fit_function, xyGrid, imgArrayFlat)

По какой-то причине Jupyter Notebook продолжает выдавать эту ошибку, и я не могу найти проблему в коде:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-61-eaa3ebdb6469> in <module>()
     17     imgArrayFlat = imgArray.ravel()    # Flatten 2D pixel data into 1D array for scipy.optimize.curve_fit
     18 
---> 19     params_opt, params_cov = curve_fit(doughnut, xyGrid, imgArrayFlat)

/usr/lib/python3/dist-packages/scipy/optimize/minpack.py in curve_fit(f, xdata, ydata, p0, sigma, absolute_sigma, check_finite, bounds, method, jac, **kwargs)
    749         # Remove full_output from kwargs, otherwise we're passing it in twice.
    750         return_full = kwargs.pop('full_output', False)
--> 751         res = leastsq(func, p0, Dfun=jac, full_output=1, **kwargs)
    752         popt, pcov, infodict, errmsg, ier = res
    753         cost = np.sum(infodict['fvec'] ** 2)

/usr/lib/python3/dist-packages/scipy/optimize/minpack.py in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)
    384     m = shape[0]
    385     if n > m:
--> 386         raise TypeError('Improper input: N=%s must not exceed M=%s' % (n, m))
    387     if epsfcn is None:
    388         epsfcn = finfo(dtype).eps

TypeError: Improper input: N=5 must not exceed M=2

Я не понимаю, что означают N и M, но я где-то читал, что эта ошибка возникает, когда точек данных меньше, чем параметров (недоопределенная система) - что здесь не так, как файлы изображений имеют около 15 x 15 = 225 точек данных каждый. Что может быть причиной проблемы?


person frankmertens    schedule 16.08.2020    source источник


Ответы (1)


Вероятно, вам нужно изменить функцию на

def fit_function(X, x0, y0, A, FWHM):
    x, y = X
    return A*np.exp(1)*4*np.log(2)*((x+x0)**2 + (y+y0)**2)/FWHM**2*np.exp(-4*np.log(2)*((x+x0)**2 + (y+y0)**2)/FWHM**2)

потому что только первая переменная рассматривается как независимая.

В настоящее время вы отправляете массив внутри переменной x, которая представляет собой np.vstack из двух одномерных массивов, следовательно, M=2: у вас есть две точки данных. В функции все остальные аргументы рассматриваются как оптимизируемые параметры (включая y!), поэтому N=5.

person Péter Leéh    schedule 16.08.2020
comment
Эй, кажется, это работает! Не могли бы вы объяснить, что происходит? Это похоже на некую упаковку/распаковку переменных, но вместо *args вы используете x, y = X... это эквивалентно (x, y) = X? - person frankmertens; 16.08.2020
comment
@frankmertens Распаковывает np.array построчно. Чтобы распаковать по столбцам, вы можете использовать x, y = X.T. Это эквивалентно (x, y) = X. - person Péter Leéh; 17.08.2020
comment
Ах, это особый синтаксис NumPy? - person frankmertens; 17.08.2020
comment
@frankmertens Нет. Попробуйте с простыми вложенными списками Python. a = [[1, 2, 3], [4, 5, 6]], c, d = a. Конечно, метод транспонирования T не будет работать для списков Python. - person Péter Leéh; 17.08.2020
comment
Потрясающе, спасибо! Кстати, есть объяснение, почему именно c, d = a, а не a = c, d? Насколько я знаю, = — это указатель между объектами, а foo = bar указывает с foo на bar. - person frankmertens; 17.08.2020
comment
@frankmertens Потому что вы хотите определить две новые переменные c и d, которые ссылаются на строки исходного списка. a = c, d не имеет смысла, c и d даже не определены. В математике это имело бы смысл, но в Python, если вы хотите создавать новые вещи, они должны быть слева от знака =. - person Péter Leéh; 17.08.2020