Scipy curve_fit 可变参数和常量参数

Scipy curve_fit with variable and constant arguments

我正在尝试使用 curve_fit 的方程式拟合数据点,该方程式具有两个可变参数和一个常量。因为我想测试常量的不同值,所以我想避免将它写入函数。

使用 Scipy 中的示例,我尝试这样做:

def func(x, a, b, c):
    return a * np.exp(-b * x) + c

a_test = 3

popt, pcov = curve_fit(func, xdata, ydata, bounds=([a_test, 0, 0], [a_test, 1., 0.5]))

但是我得到一个值错误,因为第一个参数的下限和上限相等。

有没有不使用其他库(例如 lmfit)就可以做到这一点的方法?

我不知道之前的答案是什么,但我认为你应该这样做:

import numpy as np
from scipy.optimize import *

a_test = 3

def func(x, b, c, a=a_test ):
    return a * np.exp(-b * x) + c

xdata = range(11, 17)
ydata = [a_test * np.exp(-0.8 * x) + 0.2 for x in xdata]

popt, pcov = curve_fit(func, xdata, ydata, bounds=([0, 0], [1., 0.5]))

print(popt,pcov)

这导致

popt = [0.79999036 0.19999999]
pcov = [[2.78472686e-11 4.44800146e-14]
 [4.44800146e-14 1.50965321e-16]]

编写一个函数,returns 一个用变量常量包装拟合函数的函数(是的:那是三个函数):

def func(x, a, b, c):
    return a * np.exp(-b * x) + c

def wrapperfunc(a_test):
    def tempfunc(x, b, c, a=a_test):
        return func(x, a, b, c)
    return tempfunc

a_test = 3

xdata = range(11, 17)
ydata = [a_test * np.exp(-0.8 * x) + 0.2 for x in xdata]

# Note: run `wrapperfunc`, so that the actual fitting func (`tempfunc`) is returned
popt, pcov = curve_fit(wrapperfunc(a_test), xdata, ydata, bounds=([0, 0], [1., 0.5]))

print(popt, pcov)

a_test = 4

xdata = range(11, 17)
ydata = [a_test * np.exp(-0.8 * x) + 0.2 for x in xdata]

popt, pcov = curve_fit(wrapperfunc(a_test), xdata, ydata, bounds=([0, 0], [1., 0.5]))

print(popt, pcov)

为了清楚起见,像原始问题提到的那样,使用 lmfit 可以轻松完成这类事情。这样的事情会做:

import lmfit
import numpy as np
def func(x, a, b, c):
    return a * np.exp(-b * x) + c

model = lmfit.Model(func)
params = lmfit.Parameters() 
params.add('a', value=3, vary=False)
params.add('b', value=0.5, min=0, max=1)
params.add('c', value=0.25, min=0, max=1)

# test values for a, find one with lowest chi-square
best_result, best_a, best_chisqr = None, None, 1e199
for aval in np.linspace(0, 10, 21):
    params['a'].value = aval
    result = model.fit(ydata, params, x=xdata)
    if result.chisqr < best_chisqr:
       best_chisqr = result.chisqr
       best_result = result
       best_a = aval

print(f"### best value for a = {best_a:.2f}")
print(best_result.fit_report())

请注意,尝试通过设置值的下限和上限来冻结变量会导致统计分析混淆问题中是否存在 2 个或 3 个变量。另一方面,如此处所示的循环显然是一次使用 2 个变量,但它确实忽略了 a 是一种可变参数。为了最稳健,您可能希望允许 a 变化。

使用 lmfit 的“负担”是必须 运行“pip install lmfit”,这可能需要几秒钟——甚至可能与您阅读所需的时间一样长这条消息。