为什么 curve_fit 对于 beta 函数拟合不收敛?

why curve_fit does not converge for a beta function fit?

当我尝试将 beta 函数拟合到几个点时,我的 Python 代码出现了一个小问题。问题是解决方案不收敛(结果系数为 nans),或者它什么都不做(结果与我最初的猜测相同),或者它显然适合,但适合的是与数据点完全不相似。 我一直在阅读关于 beta 函数和关于 curve_fit 的类似帖子,因为这两个都是在 Whosebug 文献中讨论的问题,但我一直无法找到解决我所遇到的特定问题的方法,所以我想知道你是否可以给我一些想法。

我有一组积分:

x = np.array([0.1, 0.3, 0.5, 0.7, 0.9, 1.1])
y = np.array([0.45112234, 0.56934313, 0.3996803 , 0.28982859, 0.19682153,
   0.]

然后我尝试使用 curve_fit 将它们与 gamma 函数相匹配,如下所示:

from scipy.optimize import curve_fit
from scipy.special import gamma as gamma
def betafunc(x,a,b,cst):
    return cst*gamma(a+b) * (x**(a-1)) * ((1-x)**(b-1))  / ( gamma(a)*gamma(b) )
popt2,pcov2 = curve_fit(betafunc,x,y,p0=(0.5,1.5,0.5))

这就是我的问题所在,因为根据我最初的猜测,我得到 popt2=[nan,nan,nan]popt2=p0,或者在绘制时不模仿的几次值完全没有数据。

我也知道 beta 函数适用于 0 < x < 1,所以我尝试重新缩放点,或者只是删除数据的最后一个点,但这也不太好。向曲线拟合添加误差或如前所述,更改初始参数也无济于事。 我还以为可能只是因为我有3个自由参数和4或5个点,但是,如图所示...

...我已经安装了另一个配置文件(也使用三个免费参数),并且没有问题,所以我不明白为什么另一个测试配置文件不起作用。非常感谢任何指导!

您的实现是针对 beta 分布 的概率密度函数(而不是 beta 函数)。它在区间 0 <= x <= 1 内定义。因此,您的独立数据(x 坐标)必须完全在此区间内。您如何确保这一点取决于您尝试做的事情的更大背景。可能的方法包括修剪或映射到间隔的某些部分。

按照您的示例,以下(修剪)运行没有错误:

import numpy as np
from scipy.optimize import curve_fit
from scipy.special import gamma as gamma
def betafunc(x,a,b,cst):
    return cst*gamma(a+b) * (x**(a-1)) * ((1-x)**(b-1))  / ( gamma(a)*gamma(b) )

x = np.array( [0.1, 0.3, 0.5, 0.7, 0.9, 1.1])
y = np.array( [0.45112234, 0.56934313, 0.3996803 , 0.28982859, 0.19682153, 0.] )


popt2,pcov2 = curve_fit(betafunc,x[:-1],y[:-1],p0=(0.5,1.5,0.5))

print popt2
print pcov2

并产生结果:

[ 1.22624727  1.74192827  0.37084996]
[[ 0.03758865  0.04888083 -0.00132468]
 [ 0.04888083  0.09142608 -0.00309165]
 [-0.00132468 -0.00309165  0.00094766]]

这也(重新缩放 x)运行没有错误:

import numpy as np
from scipy.optimize import curve_fit
from scipy.special import gamma as gamma
def betafunc(x,a,b,cst,scale):
    x = x / scale
    return cst*gamma(a+b) * (x**(a-1)) * ((1-x)**(b-1))  / ( gamma(a)*gamma(b) )

x = np.array( [0.1, 0.3, 0.5, 0.7, 0.9, 1.1])
y = np.array( [0.45112234, 0.56934313, 0.3996803 , 0.28982859, 0.19682153, 0.] )

popt2,pcov2 = curve_fit(betafunc,x,y,p0=(0.5,1.5,0.5,1.1))

print popt2
print pcov2

并产生结果:

[ 1.37100253  2.36832069  0.32337175  1.16052822]
[[ 0.04972377  0.15943756 -0.00792804  0.02550767]
 [ 0.15943756  0.71001918 -0.04180131  0.14426687]
 [-0.00792804 -0.04180131  0.00312037 -0.00983075]
 [ 0.02550767  0.14426687 -0.00983075  0.0373759 ]]

请注意,在第二个示例中,x 范围缩放也是拟合变量之一。但它也可以由您的问题决定。这完全取决于您的上下文。

同样,哪种方法适合您使用,取决于数据来源的详细信息。您选择的方法应该在您尝试拟合的数据和您希望实现的目标的上下文中具有物理意义。