Проблема в том, что ваша вторая попытка подгонки гауссиана застревает в локальном минимуме при поиске пространства параметров: 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)
Что, как вы можете видеть, обеспечивает разумное соответствие:
Вам следует написать функцию, которая может предоставить разумные оценки начальных параметров. Здесь я только что нашел максимальное значение y и использовал его для определения начальных параметров. Я нашел, что это хорошо работает для подходящих нормальных распределений, но вы могли бы рассмотреть другие методы.
Edit:
Вы также можете решить эту проблему путем масштабирования амплитуды: амплитуда настолько велика, что пространство параметров искажено, а градиентный спуск просто следует направлению наибольшего изменения амплитуды и эффективно игнорирует сигма. Рассмотрим следующий график в пространстве параметров (Цвет - это сумма квадратов невязок соответствия для заданных параметров, а белый крестик показывает оптимальное решение):
Обязательно запишите различные шкалы для осей x и y.
Нужно сделать большое количество шагов «единичного» размера по y (амплитуда), чтобы добраться до минимума из точки x, y = (0,0), где вам нужно только меньше, чем одна «единица» размер шага, чтобы добраться до минимума в х (сигма). Алгоритм просто принимает шаги по амплитуде, так как это самый крутой градиент. Когда он достигает амплитуды, которая минимизирует функцию стоимости, он просто останавливает алгоритм, поскольку он, по-видимому, сходится, и вносит небольшие изменения или вообще не вносит изменений в параметр sigma.
Одним из способов решения этой проблемы является масштабирование ваших ydata, чтобы не искажать пространство параметров: разделите ваш ydata
на 100, и вы увидите, что подгонка работает без предоставления каких-либо начальных параметров!