Python 带约束的曲线拟合
Python curve fitting with constraints
我一直在寻找 Python 带约束的曲线拟合。一种选择是使用 lmfit module and another option is to use penalization 来强制执行约束。我有以下代码,我试图在其中强制执行 a+b=3.6
作为约束。换句话说,y=3.6
when x=1
and x
is always >=1
in my case.
import numpy as np
import scipy.optimize as sio
def func(x, a, b, c):
return a+b*x**c
x = [1, 2, 4, 8, 16]
y = [3.6, 3.96, 4.31, 5.217, 6.842]
lb = np.ones(3, dtype=float)
ub = np.ones(3, dtype=float)*10.
popt, pcov = sio.curve_fit(func, x, y)
print(popt)
理想情况下,我想使用 lmfit
方法并花费大量时间尝试理解示例但未能成功。有人可以帮忙举个例子吗?
如果我对你的问题的理解正确,你想用
对一些数据进行建模
def func(x, a, b, c):
return a+b*x**c
并且对于一组特定的数据,您想要施加 a+b=3.6
的约束。你可以,只是“硬连线”,将功能更改为
def func2(x, b, c):
a = 3.6 - b
return a+b*x**c
现在您的模型函数只有两个变量:b
和 c
.
这不是很灵活,但会奏效。
使用 lmfit 可以恢复一些灵活性。做一个完全不受约束的拟合,你会说
from lmfit import Model
mymodel = Model(func)
params = mymodel.make_params(a=2, b=1.6, c=0.5)
result = mymodel.fit(y, params, x=x)
(顺便说一句:scipy.optimize.curve_fit
允许您不指定参数的初始值,并在不告诉您的情况下将它们隐式设置为 1。这是一个可怕的错误功能 - 总是给出初始值)。
如果您确实想施加约束 a+b=3.6
,您可以执行
params['a'].expr = '3.6-b'
result2 = mymodel.fit(y, params, x=x)
print(result2.fit_report())
当我使用您提供的数据执行此操作时,会打印(请注意它报告 2 个变量,而不是 3 个):
[[Model]]
Model(func)
[[Fit Statistics]]
# fitting method = leastsq
# function evals = 34
# data points = 5
# variables = 2
chi-square = 0.01066525
reduced chi-square = 0.00355508
Akaike info crit = -26.7510142
Bayesian info crit = -27.5321384
[[Variables]]
a: 3.28044833 +/- 0.04900625 (1.49%) == '3.6-b'
b: 0.31955167 +/- 0.04900626 (15.34%) (init = 1.6)
c: 0.86901253 +/- 0.05281279 (6.08%) (init = 0.5)
[[Correlations]] (unreported correlations are < 0.100)
C(b, c) = -0.994
您的代码暗示使用(但实际上并未使用)参数值的上限和下限。这些也可以用 lmfit
,如
params['b'].min = 1
params['b'].min = 10
等等。我不确定您是否需要它们,并提醒您不要将界限设置得太紧。
我一直在寻找 Python 带约束的曲线拟合。一种选择是使用 lmfit module and another option is to use penalization 来强制执行约束。我有以下代码,我试图在其中强制执行 a+b=3.6
作为约束。换句话说,y=3.6
when x=1
and x
is always >=1
in my case.
import numpy as np
import scipy.optimize as sio
def func(x, a, b, c):
return a+b*x**c
x = [1, 2, 4, 8, 16]
y = [3.6, 3.96, 4.31, 5.217, 6.842]
lb = np.ones(3, dtype=float)
ub = np.ones(3, dtype=float)*10.
popt, pcov = sio.curve_fit(func, x, y)
print(popt)
理想情况下,我想使用 lmfit
方法并花费大量时间尝试理解示例但未能成功。有人可以帮忙举个例子吗?
如果我对你的问题的理解正确,你想用
对一些数据进行建模def func(x, a, b, c):
return a+b*x**c
并且对于一组特定的数据,您想要施加 a+b=3.6
的约束。你可以,只是“硬连线”,将功能更改为
def func2(x, b, c):
a = 3.6 - b
return a+b*x**c
现在您的模型函数只有两个变量:b
和 c
.
这不是很灵活,但会奏效。
使用 lmfit 可以恢复一些灵活性。做一个完全不受约束的拟合,你会说
from lmfit import Model
mymodel = Model(func)
params = mymodel.make_params(a=2, b=1.6, c=0.5)
result = mymodel.fit(y, params, x=x)
(顺便说一句:scipy.optimize.curve_fit
允许您不指定参数的初始值,并在不告诉您的情况下将它们隐式设置为 1。这是一个可怕的错误功能 - 总是给出初始值)。
如果您确实想施加约束 a+b=3.6
,您可以执行
params['a'].expr = '3.6-b'
result2 = mymodel.fit(y, params, x=x)
print(result2.fit_report())
当我使用您提供的数据执行此操作时,会打印(请注意它报告 2 个变量,而不是 3 个):
[[Model]]
Model(func)
[[Fit Statistics]]
# fitting method = leastsq
# function evals = 34
# data points = 5
# variables = 2
chi-square = 0.01066525
reduced chi-square = 0.00355508
Akaike info crit = -26.7510142
Bayesian info crit = -27.5321384
[[Variables]]
a: 3.28044833 +/- 0.04900625 (1.49%) == '3.6-b'
b: 0.31955167 +/- 0.04900626 (15.34%) (init = 1.6)
c: 0.86901253 +/- 0.05281279 (6.08%) (init = 0.5)
[[Correlations]] (unreported correlations are < 0.100)
C(b, c) = -0.994
您的代码暗示使用(但实际上并未使用)参数值的上限和下限。这些也可以用 lmfit
,如
params['b'].min = 1
params['b'].min = 10
等等。我不确定您是否需要它们,并提醒您不要将界限设置得太紧。