Почему Сципи так плохо подходит к этой кривой? - PullRequest
0 голосов
/ 11 апреля 2020

Я пытаюсь приспособить эту функцию к некоторым данным

Это моя функция:

def first_deriv(xlist, L, k, x0):
    return [k*L*(math.e**(-k*(x+x0)))/(1+math.e**(-k*(x+x0)))**2 for x in xlist]

Вот так выглядит функция, поэтому я ожидал получить довольно хорошую подгонку. How the function looks

Это код для подгонки функции к данным

popt = curve_fit(first_deriv, list(range(len(data))), data, bounds=((0, -np.inf, -np.inf), (10**(9), +np.inf, 0)), maxfev=10000)

И вот как я ее рисую:

xdata = list(np.linspace(-100, 100, 2000))    
plt.scatter(xdata, first_deriv(xdata, popt[0][0], popt[0][1], popt[0][2]), s=1)

Границы существуют для того, чтобы сделать ответ разумным, но даже если я сделаю все границы бесконечными, это все равно даст ужасное соответствие.

Это ужасное соответствие

The bad fit

Я удивлен, как, кажется, curve_fit полностью облажается. Может кто-нибудь объяснить, почему?

Ответы [ 2 ]

2 голосов
/ 11 апреля 2020

В вашем примере есть две проблемы.

Тривиальная задача

curve_fit ожидает значения независимой переменной в качестве второго аргумента , в то время как приведенный выше код дает list(range(len(data)), что даст целочисленные значения x от 0 до длинных data. Вы заметите, что ваш точечный график указывает только go до ~ 50. Я предполагаю, что именно поэтому.

Вместо этого вы должны дать список значений независимой переменной в точках, где наблюдалось data. В зависимости от того, как data генерируется / собирается (вы не предоставляете эту информацию в своем вопросе), это может быть xdata.

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

Реальная проблема

Не все методы оптимизации одинаково подходят для всех задач. curve_fit может использовать 3 метода: 'lm, 'trf' и 'dogbox'. По умолчанию это lm, для метода Левенберга – Марквардта , , если не указаны границы , в этом случае вместо него используется 'trf', то есть метод Trust Region .

Немного поиграв с примером, я обнаружил, что 'lm' работает хорошо, а 'trf' - нет.

Например, возьмем следующий код:

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

def first_deriv(xlist, L, k, x0):
    return [k*L*(math.e**(-k*(x+x0)))/(1+math.e**(-k*(x+x0)))**2 for x in xlist]

xdata = list(np.linspace(-100, 100, 2000))
real_parameters = (320000.0, 0.1, -30.0)

fakedata = first_deriv(xdata, *real_parameters)
plt.plot(xdata, fakedata)

Который дает кривую в вашем примере выше (i sh): enter image description here

Сравнение 3 методов подтверждает, что 'lm' ищет best и восстанавливает исходные параметры:

lm_parameters = curve_fit(first_deriv, xdata, fakedata)[0]
trf_parameters = curve_fit(first_deriv, xdata, fakedata, method='trf')[0]
dogbox_parameters = curve_fit(first_deriv, xdata, fakedata, method='dogbox')[0]

plt.scatter(xdata, first_deriv(xdata, *lm_parameters), s=1, label='lm')
plt.scatter(xdata, first_deriv(xdata, *trf_parameters), s=1, label='trf')
plt.scatter(xdata, first_deriv(xdata, *dogbox_parameters), s=1, label='dogbox')
plt.legend()

enter image description here

Интересный вопрос (который, возможно, заслуживает отдельного поста) состоит в том, почему это так. Хотя я и не могу дать точного математического аргумента, игра с параметрами вашей функции предлагает некоторые грубые идеи.

Например, «расширение пика» вашей функции, кажется, позволяет всем методам работать хорошо. enter image description here enter image description here

Без сомнения, изменение параметров изменило «ландшафт пригодности» таким образом, чтобы позволить методам области доверия успешно работать.

Также возможно, что некоторые параметры самих методов 'trf' и 'dogbox' могут дать лучшие результаты. Это потребовало бы более глубокого знания методов.

Сказав, что 'lm', кажется, лучший метод для этой конкретной проблемы. Всегда важно знать, какой метод вы используете, и экспериментировать с различными для каждой новой проблемы, особенно если вы получаете плохие результаты.

2 голосов
/ 11 апреля 2020

Процедуры оптимизации могут попасть в локальные максимумы (когда любое изменение параметров вначале ухудшит подгонку, прежде чем станет лучше). Чтобы избежать этой проблемы (и ускорить вычисления), scipy.optimize.curve_fit () позволяет вам указать ваши лучшие догадки для параметров с ключевым словом p0.

Таким образом, вы должны передать значения параметров, которые вы использовали для своего графика функции выше, в curve_fit() в качестве отправной точки.

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