Гауссовские данные варьируются в зависимости от положения данных x - PullRequest
5 голосов
/ 26 марта 2019

Я с трудом пытаюсь понять, почему моя подгонка по Гауссу к набору данных (ydata) не работает должным образом, если я сдвигаю интервал значений x, соответствующих этим данным (xdata1 до * 1003)*).Gaussian записывается как:

image

where A is just an amplitude factor. Changing some of the values of the data, it is easy to make it work for both cases, but one can also easily find cases in which it does not work well for xdata1 and also in which covariance of the parameters is not estimated. I am using scipy.optimize.curve_fit in Spyder with Python 3.7.1 on Windows 7.

results from code

import numpy as np
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

xdata1 = np.linspace(-9,4,20, endpoint=True) # works fine
xdata2 = xdata1+2
ydata = np.array([8,9,15,12,14,20,24,40,54,94,160,290,400,420,300,130,40,10,8,4])

def gaussian(x, amp, mean, sigma):
    return amp*np.exp(-(((x-mean)**2)/(2*sigma**2)))/(sigma*np.sqrt(2*np.pi))

popt1, pcov1 = curve_fit(gaussian, xdata1, ydata)
popt2, pcov2 = curve_fit(gaussian, xdata2, ydata)

fig, ([ax1, ax2]) = plt.subplots(nrows=1, ncols=2,figsize=(9, 4))

ax1.plot(xdata1, ydata, 'b+:', label='xdata1')
ax1.plot(xdata1, gaussian(xdata1, *popt1), 'r-', label='fit')
ax1.legend()
ax2.plot(xdata2, ydata, 'b+:', label='xdata2')
ax2.plot(xdata2, gaussian(xdata2, *popt2), 'r-', label='fit')
ax2.legend()

1 Ответ

3 голосов
/ 26 марта 2019

Проблема в том, что ваша вторая попытка подгонки гауссиана застревает в локальном минимуме при поиске пространства параметров: curve_fit - это обертка для less_squares , которая использует градиентный спуск, чтобы минимизировать функцию стоимости, и это ответственно застрял в локальных минимумах .

Вы должны попытаться предоставить разумные начальные параметры (используя аргумент p0 curve_fit ), чтобы избежать этого:

 #...  your code

 y_max = np.max(y_data)
 max_pos = ydata[ydata==y_max][0]
 initial_guess = [y_max, max_pos, 1] # amplitude, mean, std

 popt2, pcov2 = curve_fit(gaussian, xdata2, ydata, p0=initial_guess)

Что, как вы можете видеть, обеспечивает разумное соответствие:

gaussian_fits_with_parameters

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

Edit:

Вы также можете решить эту проблему путем масштабирования амплитуды: амплитуда настолько велика, что пространство параметров искажено, а градиентный спуск просто следует направлению наибольшего изменения амплитуды и эффективно игнорирует сигма. Рассмотрим следующий график в пространстве параметров (Цвет - это сумма квадратов невязок соответствия для заданных параметров, а белый крестик показывает оптимальное решение):

full_parameter_space

Обязательно запишите различные шкалы для осей x и y.

Нужно сделать большое количество шагов «единичного» размера по y (амплитуда), чтобы добраться до минимума из точки x, y = (0,0), где вам нужно только меньше, чем одна «единица» размер шага, чтобы добраться до минимума в х (сигма). Алгоритм просто принимает шаги по амплитуде, так как это самый крутой градиент. Когда он достигает амплитуды, которая минимизирует функцию стоимости, он просто останавливает алгоритм, поскольку он, по-видимому, сходится, и вносит небольшие изменения или вообще не вносит изменений в параметр sigma.

Одним из способов решения этой проблемы является масштабирование ваших ydata, чтобы не искажать пространство параметров: разделите ваш ydata на 100, и вы увидите, что подгонка работает без предоставления каких-либо начальных параметров!

...