我正在尝试学习如何在 scipy (stats.kstest) 中使用 Kolmogorov-Smirnov 测试。对于像文档中的示例这样的简单问题,单个样本测试的测试统计量似乎是正确的,但 p 值没有意义。
这是一个示例,我针对随机生成的正态分布数据运行了 5000 次测试统计。
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
pValues = []
statistics = []
for q in range(5000):
F = stats.norm.rvs(size=5000)
res = stats.kstest(F, stats.norm.cdf, alternative='two-sided')
pValues.append(res.pvalue)
statistics.append(res.statistic)
plt.close('all')
statistics = np.array(statistics)
statCritical = 1.36/(len(F)**0.5)
print(f'fraction above critical stat ({statCritical}): ',len(statistics[statistics>statCritical])/len(statistics))
print(f'fraction below critical stat ({statCritical}): ',len(statistics[statistics<statCritical])/len(statistics))
plt.hist(statistics,bins=50)
plt.tight_layout()
plt.savefig('hist.statistic.png')
plt.close('all')
pValues = np.array(pValues)
print('fraction above pvalue 0.95: ',len(pValues[pValues>0.95])/len(pValues))
print('fraction below pvalue 0.05: ',len(pValues[pValues<0.05])/len(pValues))
plt.hist(pValues,bins=50)
plt.tight_layout()
plt.savefig('hist.pvalue.png')
我从这里获得了关键测试统计值:https://people.cs.pitt.edu/~lipschultz/cs1538/prob-table_KS.pdf
当我运行此命令时,我得到高于临界值的测试统计数据的分数约为 0.05,低于测试统计数据的分数约为 0.95(这是我的预期)。返回的 p 值本质上是均匀且随机的,介于 0 和 1 之间。我错过了什么?
您的程序是正确的,它反映了您应该期望的结果。
带有以下种子:
np.random.seed(12345)
正如您所注意到的,在一定的置信水平下,H0 将在计算中被拒绝(您选择的置信水平为
95%
,因此临界概率为 0.05
)(D > 0.019233
)。也就是说,一些抽取的样本似乎离正态性太远,无法以一定的置信度相信它们实际上是从正态性中抽取的。
使用大于临界值的
D
统计量进行测试会导致拒绝 H0。
现在,如果我们检查 p 值的分布方式,我们会确认您的观察结果,它几乎肯定是均匀分布的:
左侧观测值是在置信水平上拒绝 H0 的测试,右侧观测值是在置信水平上不能拒绝 H0 的测试。
因此,正如在置信水平
x %
所预期的那样,我们将拒绝H0的(100 - x) %
。 因此是均匀分布。 在您的情况下,几乎 95% 的试验被接受(H0 没有被拒绝),几乎 5% 的试验被拒绝。
统计量和 p 值之间的关系可以可视化,并确认您独立计算的临界值有意义:
正如您所说,p 值通常很难解释,并且它们的实现可能因软件而异。在这种情况下,您可以依赖Wikipedia的定义:
在零假设显着性检验中,p 值为 获得测试结果的概率至少与 假设零值,实际观察到的结果 假设正确
scipy.stats.kstest
中实现的相同(有关更多详细信息,请参阅底部示例)。