Python中的Kolmogorov-Smirnov测试奇怪的结果和解释

机器算法验证 Python kolmogorov-smirnov 测试 相似之处 scipy
2022-04-10 21:07:08

我很难理解 Kolmogorov-Smirnov 测试的工作原理。如果我想知道我的样本是否来自特定分布(例如来自 weibull 分布),我可以将我的显着性水平与从 scipy.stats 获得的 p 值进行比较。如果 p 值高于我选择的 alpha (5%),我的样本来自分布。如果 p 值 < 5%,它们是不同的。

在此代码示例中,我不理解结果。我的样本来自我测试的同一分布,我得到的 p 值为 0,这意味着它们来自不同的分布,这对我来说毫无意义。如果有人可以帮助我解决这个问题,那就太好了。

import scipy.stats as stats
import numpy as np

smapleData = stats.weibull_min.rvs(2.34, loc=0, scale=1, size=10000)
x = np.linspace(0, max(tmp), num=10000, endpoint=True)

stats.kstest(stats.weibull_min.pdf(x, 2.34, loc=0, scale=1), smapleData)

#-> KstestResult(statistic=0.5031, pvalue=0.0)

我读到 KS 测试可能不适用于大数据。如果有人对我如何与样本集进行比较(不知道其背后的分布)有其他想法,我将不胜感激。

2个回答

在阅读Kolmogorov-Smirnov 测试的文档时,您遇到了一些错误。

首先,您需要使用累积分布函数 (CDF),而不是概率密度函数 (PDF)。其次,您必须将 CDF 作为可调用函数传递,而不是在等间距的点网格处对其进行评估。[这不起作用,因为kstest函数假定您正在传递第二个样本以进行双样本 KS 测试。]

from functools import partial

import numpy as np
import scipy.stats as stats


# Weibull distribution parameters
c, loc, scale = 2.34, 0, 1
# sample size
n = 10_000

x = stats.weibull_min.rvs(c, loc=loc, scale=scale, size=n)

# One-sample KS test compares x to a CDF (given as a callable function)
stats.kstest(
    x,
    partial(stats.weibull_min.cdf, c=c, loc=loc, scale=scale)
)
#> KstestResult(statistic=0.0054, pvalue=0.9352)

# Two-sample KS test compares x to another sample (here from the same distribution)
stats.kstest(
    x,
    stats.weibull_min.rvs(c, loc=loc, scale=scale, size=n)
)
#> KstestResult(statistic=0.0094, pvalue=0.9291) 

@Dave 是正确的,假设检验我们不接受零假设,我们只能拒绝它或不拒绝它。关键是“不拒绝”与“接受”不同。

另一方面,说“我们有 10,000 个样本,但我们根本没有足够的证据来得出任何结论”,这听起来有点尴尬。在这个样本量下,我们期望估计是精确的(方差很小)。

请注意,这种情况有点假设。在实践中,我们很少知道真实分布或两个大样本来自与模拟中相同的分布。因此,在现实世界中,样本量约为 10k,p 值更可能很小,而不是很大。

那么,如果样本量很大且 p 值很大,我们能学到什么吗?

  • 我们了解到显着性水平α = 0.05对于大数据没有意义。n增长时保持α不变意味着我们正在寻找越来越小的影响。
  • 我们了解到——虽然我们不能接受零假设为真——但证据与“无效果”和“微不足道的效果”都是一致的。如果我们选择了样本量,以便我们有足够的能力来检测我们感兴趣的差异,那么我们也很清楚“微不足道”的含义。

您可以阅读更多关于大型数据集是否不适合假设检验的主题?.

除了另一个答案中解决的编码错误之外,我想解决帖子中的两个统计错误。

如果 p 值高于我选择的 alpha (5%),我的样本来自分布。

这是对 p 值的常见误解。我们不接受零假设。当 p 值大于时,我们根本没有足够的证据来得出任何结论。否则,您可以只收集两分,进行测试,几乎从不拒绝,并继续声称您在零假设之后证明零假设。此外,此逻辑适用于所有假设检验,而不仅仅是 KS。α

我读到 KS 测试可能不适用于大数据。

在另一个交叉验证的帖子中广泛讨论了这一点虽然该问题涉及正态分布,但逻辑适用。总结链接,大样本量为假设检验(不仅仅是 KS)提供了强大的能力来检测对客户/客户/审阅者/老板不具有实际重要性或不感兴趣的微小差异。然而,这只发生在原假设稍微不正确的情况下,比如当真实的如果原假设为真,则 KS 检验完全符合预期,正如我将在模拟中演示的那样。μ=0μ=0.1

library(ggplot2)
set.seed(2022)
B <- 5000
N <- 25000
ps <- rep(NA, B)
for (i in 1:B){
  
  # Simulate some Weibull data
  # 
  x <- rweibull(N, 2.34, 1)
  
  # KS-test the data for having the specified Weibull distribution
  #
  ps[i] <- ks.test(x, pweibull, shape = 2.34, scale = 1)$p.value
  
  if (i %% 25 == 0 | i < 5 | B - i < 5){
    print(paste(i/B*100, "% complete", sep = ""))
  }
}
d <- data.frame(ps = ps, CDF = ecdf(ps)(ps), Distribution = "Weibull")
ggplot(d, aes(x = ps, y = CDF, col = Distribution)) +
  geom_line() +
  geom_abline(slope = 1, intercept = 0) +
  theme_bw()

![在此处输入图像描述

由于原假设为真,因此 KS 检验拒绝了大约正确的次数(对于任何水平,而不仅仅是),如 p 值的外观 CDF 所示。的样本量来增强 KS 测试,而不是你的,但 KS 并没有被压倒。α0.05U(0,1)2500010000

现在让我们稍微调整一下模拟。对角线上方的图表示检测差异的能力。y=x

library(ggplot2)
set.seed(2022)
B <- 5000
N <- 25000
ps <- rep(NA, B)
for (i in 1:B){
  
  # Simulate some Weibull data
  # 
  x <- rweibull(N, 2.34, 1)
  
  # KS-test the data for having the specified Weibull distribution
  #
  ps[i] <- ks.test(x, pweibull, shape = 2.3, scale = 1)$p.value
  
  if (i %% 25 == 0 | i < 5 | B - i < 5){
    print(paste(i/B*100, "% complete", sep = ""))
  }
}
d <- data.frame(ps = ps, CDF = ecdf(ps)(ps), Distribution = "Weibull 2.3")
ggplot(d, aes(x = ps, y = CDF, col = Distribution)) +
  geom_line() +
  geom_abline(slope = 1, intercept = 0) +
  theme_bw()

在此处输入图像描述

我不会告诉你是否应该关心 vs,但即使你不关心,KS 测试肯定会关心!2.32.34