#numpy #scipy #curve-fitting
#numpy #scipy #подгонка кривой
Вопрос:
Я выполняю подгонку кривой с scipy.optimize.leastsq
помощью . Например. для гауссовского:
def fitGaussian(x, y, init=[1.0,0.0,4.0,0.1]):
fitfunc = lambda p, x: p[0]*np.exp(-(x-p[1])**2/(2*p[2]**2)) p[3] # Target function
errfunc = lambda p, x, y: fitfunc(p, x) - y # Distance to the target function
final, success = scipy.optimize.leastsq(errfunc, init[:], args=(x, y))
return fitfunc, final
Теперь я хочу при необходимости исправить значения некоторых параметров в подгонке. Я обнаружил, что предложения заключаются в использовании другого пакета lmfit, которого я хочу избежать, или являются очень общими, как здесь .
Поскольку мне нужно решение, которое
- работает с numpy / scipy (никаких дополнительных пакетов и т. Д.)
- не зависит от самих параметров,
- является гибким, в котором параметры фиксированы или нет,
Я придумал следующее, используя условие для каждого из параметров:
def fitGaussian2(x, y, init=[1.0,0.0,4.0,0.1], fix = [False, False, False, False]):
fitfunc = lambda p, x: (p[0] if not fix[0] else init[0])*np.exp(-(x-(p[1] if not fix[1] else init[1]))**2/(2*(p[2] if not fix[2] else init[2])**2)) (p[3] if not fix[3] else init[3])
errfunc = lambda p, x, y: fitfunc(p, x) - y # Distance to the target function
final, success = scipy.optimize.leastsq(errfunc, init[:], args=(x, y))
return fitfunc, final
Хотя это работает нормально, это не практично и не красиво.
Итак, мой вопрос: существуют ли лучшие способы выполнения подгонки кривой в scipy для фиксированных параметров? Или существуют обертки, которые уже включают такое исправление параметров?
Комментарии:
1. Было бы неплохо иметь эту функциональность в scipy, но я не уверен, существует ли она. Из любопытства, почему вы хотите избежать lmfit? По моему опыту, это довольно просто использовать.
2. Причина, по которой я хочу избегать других пакетов, заключается в том, что мне нужно убедиться, что они правильно установлены на любом из компьютеров, на которых работает эта программа.
Ответ №1:
При использовании scipy
нет встроенных опций, о которых я знаю. Вам всегда придется выполнять обходной путь, подобный тому, который вы уже сделали.
Однако, если вы готовы использовать пакет-оболочку, могу ли я порекомендовать свой собственный symfit
? Это оболочка scipy
с удобочитаемостью и меньшим количеством шаблонного кода в качестве основных принципов. В symfit
, ваша проблема будет решена как:
from symfit import parameters, variables, exp, Fit, Parameter
a, b, c, d = parameters('a, b, c, d')
x, y = variables('x, y')
model_dict = {y: a * exp(-(x - b)**2 / (2 * c**2)) d}
fit = Fit(model_dict, x=xdata, y=ydata)
fit_result = fit.execute()
Линия a, b, c, d = parameters('a, b, c, d')
образует четыре Parameter
объекта. Чтобы, например, вернуть параметру c
его начальное значение, выполните следующие действия в любом месте перед вызовом fit.execute()
:
c.value = 4.0
c.fixed = True
Таким образом, возможным конечным результатом может быть:
from symfit import parameters, variables, exp, Fit, Parameter
a, b, c, d = parameters('a, b, c, d')
x, y = variables('x, y')
c.value = 4.0
c.fixed = True
model_dict = {y: a * exp(-(x - b)**2 / (2 * c**2)) d}
fit = Fit(model_dict, x=xdata, y=ydata)
fit_result = fit.execute()
Если вы хотите быть более динамичным в своем коде, вы можете Parameter
сразу создавать объекты с помощью:
c = Parameter(4.0, fixed=True)
Для получения дополнительной информации ознакомьтесь с документами: http://symfit.readthedocs.io/en/latest/tutorial.html#simple-example
Ответ №2:
Приведенный выше пример с использованием symfit, несомненно, будет просто синтаксисом подхода подгонки, однако действительно ли приведенный пример ограничивает переменную c?
Если вы посмотрите fit_result.param
, вы получите следующее:
OrderedDict([('a', 16.374368575343127),
('b', 0.49201249437123556),
('c', 0.5337962977235504),
('d', -9.55593614465743)])
Параметр c не равен 4.0.
Комментарии:
1. На самом деле это не ответ, не так ли? Вместо этого вы можете прокомментировать другой ответ, чтобы попросить разъяснений. Но в любом случае symfit — это не то, что задает этот вопрос.
2. Это оказалось ошибкой в версии 0.4.0 и теперь исправлено :). Но @ImportanceOfBeingErnest прав в том, что это должен быть комментарий к моему ответу, а не отдельный ответ.