我有一些数据{x_i,y_i}
,我想拟合模型函数y=f(x,a,b,c)
,以找到参数(a,c)
的最佳拟合值;但是,它们三个并不完全独立,而是约束1<b
,0<=c<1
和g(a,c)>0
,其中g
是“好”函数。我如何在Python中实现这一点,因为使用curve_fit不能直接放置参数约束?
我一直在用lmfit进行阅读,但是我只看到像1<b,0<=c<1
这样的数值约束,而没有看到g(a,c)>0
那样的数值约束,这是最重要的。
我有一些数据{x_i,y_i}
,我想拟合模型函数y=f(x,a,b,c)
,以找到参数(a,c)
的最佳拟合值;但是,它们三个并不完全独立,而是约束1<b
,0<=c<1
和g(a,c)>0
,其中g
是“好”函数。我如何在Python中实现这一点,因为使用curve_fit不能直接放置参数约束?
我一直在用lmfit进行阅读,但是我只看到像1<b,0<=c<1
这样的数值约束,而没有看到g(a,c)>0
那样的数值约束,这是最重要的。
如果我理解正确,那么您有
def g(a,b,c):
c1 = (1.0 - c)
cx = 1/c1
c2 = 2*c1
g = a*a*b*gamma(2+cx)*gamma(cx)/gamma(1+3/c2)-b*b/(1+b**c2)**(1/c2)
return g
如果是这样,并且数学正确,则可以表示为
a = sqrt((g+b*b/(1+b**c2)**(1/c2))*gamma(1+3/c2)/(b*gamma(2+cx)*gamma(cx)))
这就是说,您可以将您的问题视为具有变量 g
且> 0且值为a
通过上述表达式从b
,c
和g
衍生而来。
您可以使用lmfit
及其基于表达式的约束机制。与
gamma
函数
from lmfit import Parameters
from scipy.special import gamma
params = Parameters()
params._asteval.symtable['gamma'] = gamma
,然后设置带有边界和约束的参数。我可能会按照上面的数学方法进行更好的调试,并使用类似以下内容的方法:
params.add('b',1.5,min=1)
params.add('c',0.4,min=0,max=1)
params.add('g',0.2,min=0)
params.add('c1',expr='1-c')
params.add('cx',expr='1.0/c1')
params.add('c2',expr='2*c1')
params.add('gprod',expr='b*gamma(2+cx)*gamma(cx)/gamma(1+3/c2)')
params.add('bfact',expr='(1+b**c2)**(1/c2)')
params.add('a',expr='sqrt(g+b*b/(bfact*gprod))')
请注意,这给出了3个实际变量(现在为g
,b
和c
),并根据这些变量计算出很多派生值,包括a
。我当然会检查所有的数学。看来您对negative**fractional_power
,sqrt(negitive)
和gamma(-1)
而言是安全的,但是请注意这些可能会破坏适合度的可能性。
您可以将所有这些都嵌入到拟合函数中,但是使用约束表达式可以使您独立于如何定义拟合函数或模型函数来约束参数值。
希望有帮助。同样,如果这不能达到您想要的目的,请发布有关您要施加的约束的更多详细信息。
,就像詹姆斯·菲利普斯(James Phillips)一样,我将建议SciPy的curve_fit
。但是,定义函数的方式是约束本身之一,而SciPy的边界仅根据输入变量来定义。
函数的形式到底是什么?是否可以对它们进行转换,以便可以使用边界的标准定义,然后反转转换以提供所需的原始形式的功能?
在尝试使用SciPy的curve_fit
拟合指数回归时遇到了一个相关问题。参数搜索算法以线性方式变化,并且很难建立梯度。如果我编写的函数适合我想要的函数的对数,则使curve_fit起作用要容易得多。然后,在我的最后工作中,我采用了拟合函数的指数。
同样的策略可能对您有用。预测 ln(y)。该函数的值可以是无界的。然后,对于最终结果,输出 exp(ln(y))= y 。