scipy leastsq约束ks_2samp

时间:2014-04-08 19:00:08

标签: python statistics scipy

我想用两个高斯的总和来拟合直方图,两个高斯都具有不同的幅度,平均值和偏差。为此,我使用了scipy的curve_fit,但之后的KS测试非常糟糕。这主要是因为前几个(如在最负的x值中)值不是很准确,因此累积函数是偏离的。我还注意到累积功能下降了20%,因此KS测试的准确结果是不可能的。

然后我尝试在this question之后对被积函数进行约束。我得到的相关代码如下(没有导入和绘制部分):

def residuals(p, x,y):
    integral = quad( gauss2, -300, 300, args= (p[0],p[1],p[2],p[3],p[4],p[5]))[0]
    penalization = abs(1-integral)*10000
    print penalization
    return y - gauss2(x, p[0],p[1],p[2],p[3],p[4],p[5] ) - penalization
def gauss2(x,A, mu, sigma, A2, mu2, sigma2):
    if A2<0:
      return 1000
    return A*np.exp(-(x-mu)**2/(2.*sigma**2))+ A2*np.exp(-(x-mu2)**2/(2.*sigma2**2))

hist, bin_edges = np.histogram(data, normed=True, bins=bins)
hist_cm=np.cumsum(hist)
bin_centres = (bin_edges[:-1] + bin_edges[1:])/2
coeff, pcov2 = leastsq(residuals, x0=(0.01,0.,60.,0.01,150.,40.) ,args=(bin_centres, hist)
hist_fit = gauss2(bin_centres, *coeff)
hist_fit_cm=np.cumsum(hist_fit)
KStest= stats.ks_2samp(hist_cm,hist_fit_cm)

这导致非常好的估计,并且P值为0.629。据我所知,这意味着直方图和拟合来自相同数据的变化为62.9%,这是正确的吗?

现在我认为我可以通过不惩罚被积函数而不是惩罚P值来改进答案。为此,我使用以下内容更改了def residuals

def residuals(p, x,y):
    global bin_centres #its global defined, so should be good
    iets = np.cumsum(gauss2(bin_centres,p[0],p[1],p[2],p[3],p[4],p[5]))
    pizza=stats.ks_2samp(np.cumsum(y),iets)[1]
    penalization = 1000*(1-pizza)
    return y - gauss2(x, p[0],p[1],p[2],p[3],p[4],p[5] ) - penalization

由于P值(我称之为pizza)应尽可能接近1,penalization会变得更小,P值更高。但这会产生不太有意义的结果:P值变为0.160。当绘制它更糟糕时:两个尖峰,而不是我用第一种方法获得的平滑拟合。

KS考试是一种很好的惩罚方法,而不是被积函数吗?那怎么能以一种好的方式实现呢?

1 个答案:

答案 0 :(得分:0)

(简要回答,据我所知,阅读代码)

第一个惩罚penalization = abs(1-integral)*10000是对总积分的约束。我认为这与强加A + A2 == 1相同,因此gauss2中的混合物与一个混合。没有约束的替代方案是直接通过例如使用Logit函数来实现混合概率。

Kolmogorov-Smirnov惩罚使用L1距离并惩罚经验和参数cdf之间的最大偏差,大约(*)

L1 = np.max(np.abs(np.cumsum(y) - iets))

p值只是L1距离的单调变换,但会有不同的曲率,并会有不同的惩罚。

(*)实际计算直接查看所有步骤。

除此之外:Kolmogorov-Smirnov测试设计用于连续而非离散或分箱变量。适当的距离测量将基于卡方检验或功率发散。但是,这仅影响ks_2samp作为假设检验,而不是仅仅将其用作距离度量。

另一方面:可以直接使用norm.cdf替换integ.quad的使用。