使用频率、BIN、CDF和Python的卡方检验
我试图从头开始为Beta分布编写一个卡方拟合优度测试,而不使用任何外部函数。下面的代码报告适合的“1”,即使scipy.stats中的kstest返回零。数据是正态分布的,所以我的函数也应该返回零使用频率、BIN、CDF和Python的卡方检验,python,statistics,Python,Statistics,我试图从头开始为Beta分布编写一个卡方拟合优度测试,而不使用任何外部函数。下面的代码报告适合的“1”,即使scipy.stats中的kstest返回零。数据是正态分布的,所以我的函数也应该返回零 import numpy as np from scipy.stats import chi2 from scipy.stats import beta from scipy.stats import kstest from scipy.stats import norm preds = norm.
import numpy as np
from scipy.stats import chi2
from scipy.stats import beta
from scipy.stats import kstest
from scipy.stats import norm
preds = norm.rvs(5,2,size=200)
preds.sort()
bin_size = 30
bins = np.linspace(0,10,bin_size)
counts = np.digitize(preds, bins)
mean = 5
var = 2
sum = 0
for i in range(len(bins)-1):
p = beta.cdf(bins[i+1], mean, var) - beta.cdf(bins[i], mean, var)
freq = len(counts[counts==i]) / float(len(counts))
sum = sum + ((freq - p)**2)/p
dof = len(counts)-2
pval = 1 - chi2.cdf(sum, dof)
print pval
在代码中,我创建了容器,根据容器测量频率,使用Beta分布CDF计算预期频率,并将其相加,得到X^2测试统计数据
kstest调用是
print kstest(preds, 'beta', [mean, var])
我做错了什么
谢谢,问题在于DOF定义: dof=长度(preds)-2
这是正确的选择。此外,为了得到一致的“0”结果,我必须将垃圾箱大小减少到15。众所周知,Chi^2测试对料仓尺寸非常敏感 我认为您对自己问题的回答不正确,而且您的代码中存在一系列问题 首先,根据您的实现,使用
len(counts)-2
计算的dof与len(preds)-2
相同。所以改变这一点没有任何区别
其次,要对参数拟合进行Chi^2测试,您需要构造多个MECE的箱子,这意味着箱子之间没有重叠,它们共同跨越X
的所有可能值。但是,通过使用bins=np.linspace(0,10,bin_size)
设置您的箱子,您强制最右边的箱子停在10
。而高斯分布的范围是-inf到inf。因此,您生成的随机数有可能超过10
但与此相比,这可能不是什么问题:按照惯例,每个箱子的计数数至少必须为5。然而,使用您的方法来计算落入垃圾箱中的数字(这里您设置为30个垃圾箱)可能并且实际上几乎总是数字低于5,甚至0。任何箱子中的0个计数都会导致后续的求和
计算结果为无穷大,这可能会导致拒绝,无论拟合是好是坏。我认为这就是为什么在将dof更改为len(preds)-2
后,会得到一个0,只是碰巧在箱子计数中至少有一个0
另一个问题是Chi^2的计算。我认为您不使用频率,而是使用每个箱子中的实际计数:
p = beta.cdf(bins[i+1], mean, var) - beta.cdf(bins[i], mean, var)
p = p*200
freq = len(counts[counts==i])
sum = sum + ((freq - p)**2)/p
因此p
和freq
都是每个类别中的计数数,而不是相对频率。但我对此并不完全确定
最后,自由度的定义是箱数-参数拟合数(此处为2)-1。
所以如果你有10个箱子,
dof=10-2-1=7
。在您的代码中,这是'200-2=198'。具有如此大自由度的chi^2分布非常平坦,这意味着您需要非常大的chi^2值来拒绝拟合。这就是使用代码得到1的原因。我的函数的输出为“1”,kstest调用的输出为(0.97653486524680988,0.0)。