我想用两个高斯的总和来拟合直方图,两个高斯都具有不同的幅度,平均值和偏差。为此,我使用了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考试是一种很好的惩罚方法,而不是被积函数吗?那怎么能以一种好的方式实现呢?
答案 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的使用。