← 返回《数据科学的统计基础》
📑 查看全课大纲(第 28 / 41 节)

Kolmogorov检验

约 18 分钟

📺 正在播放小象官方高清录播(支持倍速与清晰度调节)

Kolmogorov检验

小象实战讲义 · 数据科学的统计基础

在数据科学实践中,我们常常需要判断一组观测数据是否服从某个特定的理论分布。例如,检验一组测量误差是否服从正态分布,或者检验一组随机数是否来自均匀分布。本节介绍的 Kolmogorov检验(又称K-S检验)是一种基于经验分布函数的非参数检验方法,它直接比较样本经验分布函数与理论分布函数之间的最大偏差,从而对总体的分布做出判断。学完本节,你将掌握K-S检验的原理、步骤及其与卡方拟合优度检验的区别,并能使用Python(SciPy)对实际数据进行分布拟合检验。

💡 核心导读

  • 检验目标:检验样本是否来自一个完全已知的连续型分布(分布函数F0(x)F_0(x)不含任何未知参数)。
  • 核心思想:基于经验分布函数是总体分布函数的优良估计这一事实,构造衡量两者差异的统计量。
  • 关键统计量Dn=supxFn(x)F0(x)D_n = \sup_{x} |F_n(x) - F_0(x)|,即经验分布函数与理论分布函数之间的最大绝对偏差
  • 检验原理:当原假设成立(样本来自F0(x)F_0(x))时,DnD_n应较小。若DnD_n过大,则拒绝原假设。
  • 应用对比:K-S检验适用于小样本、连续分布且分布完全已知的情形,是卡方拟合优度检验的有力补充。

从经验分布函数到Kolmogorov检验

经验分布函数:总体分布的“镜子”

X1,X2,,XnX_1, X_2, \ldots, X_n是来自总体分布函数F(x)F(x)的独立同分布样本。经验分布函数 Fn(x)F_n(x)定义为: Fn(x)=1ni=1nI(Xix)F_n(x) = \frac{1}{n} \sum_{i=1}^{n} I(X_i \le x) 其中I()I(\cdot)为示性函数,当XixX_i \le x时取值为1,否则为0。Fn(x)F_n(x)是一个阶梯函数,在每一个样本点处跳跃1/n1/n

根据格列文科定理,当nn \to \infty时,有 supxFn(x)F(x)a.s.0\sup_{x} |F_n(x) - F(x)| \xrightarrow{a.s.} 0 这意味着经验分布函数Fn(x)F_n(x)以概率1一致收敛于总体分布函数F(x)F(x),是F(x)F(x)的优良估计。

对于固定的xxFn(x)F_n(x)F(x)F(x)的无偏且相合估计。由中心极限定理可知, n[Fn(x)F(x)]dN(0,F(x)[1F(x)])\sqrt{n}[F_n(x) - F(x)] \xrightarrow{d} N(0, F(x)[1-F(x)]) 这为后续构造检验统计量提供了理论基础。

Kolmogorov检验的基本原理

我们关心如下假设检验问题: H0:F(x)=F0(x)vsH1:F(x)F0(x)H_0: F(x) = F_0(x) \quad \text{vs} \quad H_1: F(x) \neq F_0(x) 其中F0(x)F_0(x)是一个完全已知的连续型分布函数(不含任何未知参数)。

既然Fn(x)F_n(x)F(x)F(x)的优良估计,那么当H0H_0成立时,Fn(x)F_n(x)F0(x)F_0(x)的差异应该很小。很自然地,我们可以用两者之间的最大绝对偏差来衡量这种差异: Dn=supxFn(x)F0(x)D_n = \sup_{x} |F_n(x) - F_0(x)| DnD_n被称为Kolmogorov-Smirnov统计量。它是一个仅与样本量nn有关的随机变量。

检验的拒绝域构造为: W={Dnc}W = { D_n \ge c } 其中临界值cc由给定的显著性水平α\alpha决定,满足PH0(Dnc)=αP_{H_0}(D_n \ge c) = \alpha。直观上,如果观测到的DnD_n值过大,说明经验分布与理论分布偏离太远,我们有理由拒绝“样本来自F0(x)F_0(x)”的原假设。

检验统计量的分布与拒绝域

DnD_n的精确分布与计算

H0H_0成立且F0(x)F_0(x)连续的前提下,DnD_n的精确分布已被导出,但其表达式较为复杂,通常通过递推关系或统计软件进行计算。对于任意d0d \ge 0,精确概率P(Dnd)P(D_n \le d)可以通过算法求得。

在实际应用中,我们通常关注其大样本渐近分布。Kolmogorov在1933年证明了以下重要定理:

定理(Kolmogorov分布):若F0(x)F_0(x)连续且H0H_0成立,则当nn \to \infty时, limnP(nDnλ)=K(λ),λ>0\lim_{n \to \infty} P(\sqrt{n} D_n \le \lambda) = K(\lambda), \quad \lambda > 0 其中K(λ)K(\lambda)是Kolmogorov分布函数,其表达式为: K(λ)=12j=1(1)j1exp(2j2λ2)K(\lambda) = 1 - 2 \sum_{j=1}^{\infty} (-1)^{j-1} \exp(-2 j^2 \lambda^2)λ0\lambda \le 0时,K(λ)=0K(\lambda) = 0

由于DnD_n的取值范围为[0,1][0, 1],在实际使用渐近公式时,我们通常用以下近似: P(Dnd)K(nd)=12j=1(1)j1exp(2j2nd2),0<d<1P(D_n \le d) \approx K(\sqrt{n} d) = 1 - 2 \sum_{j=1}^{\infty} (-1)^{j-1} \exp(-2 j^2 n d^2), \quad 0 < d < 1 并且有:

  • d1d \ge 1时,P(Dnd)=1P(D_n \le d) = 1
  • d0d \le 0时,P(Dnd)=0P(D_n \le d) = 0

临界值的确定与检验步骤

给定显著性水平α\alpha(如0.05),临界值cc满足PH0(Dnc)=αP_{H_0}(D_n \ge c) = \alpha,即PH0(Dnc)=1αP_{H_0}(D_n \le c) = 1 - \alpha。因此, cλ1αnc \approx \frac{\lambda_{1-\alpha}}{\sqrt{n}} 其中λ1α\lambda_{1-\alpha}是Kolmogorov分布K(λ)K(\lambda)1α1-\alpha分位数,可通过查表或软件获得。

Kolmogorov检验的实施步骤

  1. 提出假设H0:F(x)=F0(x)H_0: F(x) = F_0(x) vs H1:F(x)F0(x)H_1: F(x) \neq F_0(x)
  2. 计算统计量:基于样本观测值x1,x2,,xnx_1, x_2, \ldots, x_n,计算Dn=supxFn(x)F0(x)D_n = \sup_x |F_n(x) - F_0(x)|
  3. 确定拒绝域:对于给定的α\alpha,查Kolmogorov检验临界值表得cc,或计算p值。
  4. 做出决策:若DncD_n \ge c(或p值 <α< \alpha),则拒绝H0H_0;否则不拒绝H0H_0

DnD_n的实用计算公式

由于Fn(x)F_n(x)是阶梯函数,F0(x)F_0(x)是连续增函数,DnD_n的计算可以简化为只需求解有限个点上的差值。将样本按升序排列得到次序统计量X(1)X(2)X(n)X_{(1)} \le X_{(2)} \le \cdots \le X_{(n)},则 Dn=max1in{max(Fn(X(i))F0(X(i)),Fn(X(i1))F0(X(i)))}D_n = \max_{1 \le i \le n} \left{ \max\left( \left| F_n(X_{(i)}) - F_0(X_{(i)}) \right|, \left| F_n(X_{(i-1)}) - F_0(X_{(i)}) \right| \right) \right} 其中Fn(X(i))=i/nF_n(X_{(i)}) = i/nFn(X(0))=0F_n(X_{(0)}) = 0。更简洁的公式为: Dn=max1in{max(inF0(X(i)),F0(X(i))i1n)}D_n = \max_{1 \le i \le n} \left{ \max\left( \frac{i}{n} - F_0(X_{(i)}), , F_0(X_{(i)}) - \frac{i-1}{n} \right) \right}

实例演示与Python实现

例题:均匀分布检验

在显著性水平α=0.1\alpha=0.1下,检验以下10个数据是否来自区间[0,1][0,1]上的均匀分布U(0,1)U(0,1)0.12,0.18,0.06,0.33,0.72,0.92,0.44,0.39,0.26,0.530.12, 0.18, 0.06, 0.33, 0.72, 0.92, 0.44, 0.39, 0.26, 0.53

分析:待检验分布F0(x)=xF_0(x) = x0x10 \le x \le 1)是完全已知的连续分布,且样本量n=10n=10较小,适合使用Kolmogorov检验。

手工计算步骤

  1. 将数据排序:X(1)=0.06,X(2)=0.12,,X(10)=0.92X_{(1)}=0.06, X_{(2)}=0.12, \ldots, X_{(10)}=0.92
  2. 计算F0(X(i))=X(i)F_0(X_{(i)}) = X_{(i)}(因为均匀分布U(0,1)U(0,1)的分布函数为F0(x)=xF_0(x)=x)。
  3. 计算Δi=max(inX(i),X(i)i1n)\Delta_i = \max\left( \frac{i}{n} - X_{(i)}, X_{(i)} - \frac{i-1}{n} \right)
  4. 找出最大的Δi\Delta_i作为DnD_n

计算过程如下表所示:

iiX(i)X_{(i)}i/ni/n(i1)/n(i-1)/ninX(i)\frac{i}{n} - X_{(i)}X(i)i1nX_{(i)} - \frac{i-1}{n}Δi\Delta_i
10.060.10.00.040.060.06
20.120.20.10.080.020.08
30.180.30.20.12-0.020.12
40.260.40.30.14-0.040.14
50.330.50.40.17-0.070.17
60.390.60.50.21-0.110.21
70.440.70.60.26-0.160.26
80.530.80.70.27-0.170.27
90.720.90.80.18-0.080.18
100.921.00.90.080.020.08

最大差值Dn=maxiΔi=0.27D_n = \max_i \Delta_i = 0.27(发生在i=8i=8处)。

  1. 查表决策:查Kolmogorov检验临界值表,当n=10,α=0.1n=10, \alpha=0.1时,临界值c0.3687c \approx 0.3687。由于Dn=0.27<0.3687D_n = 0.27 < 0.3687,故不拒绝H0H_0,认为该样本可以认为来自U(0,1)U(0,1)分布。

Python实现

使用SciPy库可以方便地进行Kolmogorov检验。scipy.stats模块中的kstest函数专门用于此检验。

import numpy as np
from scipy import stats

# 样本数据
data = np.array([0.12, 0.18, 0.06, 0.33, 0.72, 0.92, 0.44, 0.39, 0.26, 0.53])

# 执行Kolmogorov检验,检验是否服从均匀分布 U(0,1)
# 'uniform'指定分布类型,args=(0, 1)指定均匀分布的区间起点和长度
statistic, p_value = stats.kstest(data, 'uniform', args=(0, 1))

print("Kolmogorov-Smirnov检验结果")
print(f"检验统计量 D_n = {statistic:.4f}")
print(f"P值 = {p_value:.4f}")

# 在显著性水平 alpha=0.1 下做出决策
alpha = 0.1
if p_value < alpha:
    print(f"由于P值({p_value:.4f}) < α({alpha}),拒绝原假设,认为样本不来自U(0,1)分布。")
else:
    print(f"由于P值({p_value:.4f}) ≥ α({alpha}),不拒绝原假设,认为样本可以来自U(0,1)分布。")

# 验证:手动计算D_n并与SciPy结果比较
sorted_data = np.sort(data)
n = len(data)
i_over_n = np.arange(1, n+1) / n
i_minus1_over_n = np.arange(0, n) / n

# 理论分布函数值(U(0,1))
F0 = sorted_data  # 因为F0(x)=x

# 计算两个方向的差值
diff1 = np.abs(i_over_n - F0)
diff2 = np.abs(F0 - i_minus1_over_n)

# 取最大值
D_manual = np.max(np.column_stack((diff1, diff2)))
print(f"\n手动计算的 D_n = {D_manual:.4f}")
print(f"与SciPy结果一致: {np.isclose(statistic, D_manual)}")

运行上述代码,输出结果如下:

Kolmogorov-Smirnov检验结果
检验统计量 D_n = 0.2700
P值 = 0.3891
由于P值(0.3891) ≥ α(0.1),不拒绝原假设,认为样本可以来自U(0,1)分布。

手动计算的 D_n = 0.2700
与SciPy结果一致: True

SciPy计算得到的p值为0.3891,远大于0.1,因此不拒绝原假设,结论与手工查表一致。

Kolmogorov检验的深入讨论与比较

与卡方拟合优度检验的比较

Kolmogorov检验与卡方拟合优度检验是两种常用的分布检验方法,各有其适用范围和优缺点:

  1. 分布类型

    • K-S检验:要求F0(x)F_0(x)连续分布完全已知(不含未知参数)。
    • 卡方检验:可用于连续或离散分布,且允许F0(x)F_0(x)含有未知参数(需先估计)。
  2. 样本信息利用

    • K-S检验:基于经验分布函数,利用了样本的全部顺序信息,没有信息损失
    • 卡方检验:需将数据分组,损失了组内信息,且分组方式可能影响检验结果。
  3. 样本量要求

    • K-S检验:适用于小样本情况。
    • 卡方检验:通常要求样本量较大(如n30n \ge 30),且每组的期望频数不能太小。
  4. 检验功效

    • F0(x)F_0(x)为完全已知的连续分布时,K-S检验通常比卡方检验更有效(功效更高)。
  5. 多维扩展

    • K-S检验:难以直接推广到高维数据。
    • 卡方检验:处理高维列联表时与一维情形类似,具有一定优势。

重要注意事项与扩展

  1. 未知参数问题:若F0(x)F_0(x)含有未知参数(如检验是否服从N(μ,σ2)N(\mu, \sigma^2),但μ,σ2\mu, \sigma^2未知),标准的K-S检验不适用,因为此时DnD_n的分布会发生变化。此时应使用卡方拟合优度检验,或使用针对特定分布(如正态分布、指数分布)修正的K-S检验(如Lilliefors检验)。

  2. 两样本K-S检验:K-S检验可推广到比较两个独立样本是否来自同一分布。设X1,,XmFX_1, \ldots, X_m \sim FY1,,YnGY_1, \ldots, Y_n \sim G,检验H0:F=GH_0: F = G。构造统计量: Dm,n=supxFm(x)Gn(x)D_{m,n} = \sup_{x} |F_m(x) - G_n(x)| 其中Fm(x)F_m(x)Gn(x)G_n(x)分别为两个样本的经验分布函数。该检验称为两样本K-S检验Smirnov检验

  3. 其他基于经验分布的统计量:除了DnD_n,还可构造其他衡量Fn(x)F_n(x)F0(x)F_0(x)差异的统计量,如:

    • Cramér-von Mises统计量:Wn2=n[Fn(x)F0(x)]2dF0(x)W_n^2 = n \int_{-\infty}^{\infty} [F_n(x) - F_0(x)]^2 dF_0(x)
    • Anderson-Darling统计量:An2=n[Fn(x)F0(x)]2F0(x)[1F0(x)]dF0(x)A_n^2 = n \int_{-\infty}^{\infty} \frac{[F_n(x) - F_0(x)]^2}{F_0(x)[1-F_0(x)]} dF_0(x) 这些统计量对分布尾部的差异更为敏感。

📝 动手练一练

  1. 单样本K-S检验练习
    某工厂生产一种零件,其长度规格要求服从正态分布N(10.0,0.22)N(10.0, 0.2^2)。现随机抽取15个零件,测得长度(单位:mm)如下:

    10.12, 9.98, 10.05, 10.21, 9.92, 10.08, 10.15, 9.89, 10.03, 10.18, 9.95, 10.11, 10.02, 9.97, 10.09

    在显著性水平α=0.05\alpha=0.05下,使用Python的K-S检验判断这批零件的长度是否服从指定正态分布。

    参考答案

    import numpy as np
    from scipy import stats
    
    data = np.array([10.12, 9.98, 10.05, 10.21, 9.92, 10.08, 10.15, 
                     9.89, 10.03, 10.18, 9.95, 10.11, 10.02, 9.97, 10.09])
    
    # 注意:K-S检验要求分布完全已知,这里均值和方差已给定
    # 新版SciPy推荐传入冻结分布的cdf函数('norm'+args写法在新版本中会报错)
    stat, p = stats.kstest(data, stats.norm(loc=10.0, scale=0.2).cdf)
    
    print(f"K-S统计量: {stat:.4f}")
    print(f"P值: {p:.4f}")
    
    if p < 0.05:
        print("拒绝H0,零件长度不服从N(10.0, 0.2^2)分布。")
    else:
        print("不拒绝H0,零件长度可以认为服从N(10.0, 0.2^2)分布。")
  2. 两样本K-S检验练习
    有两台机器生产同种零件,从两台机器各抽取产品测量其直径(单位:mm):

  • 机器A:10.1, 10.3, 9.8, 10.0, 10.2, 9.9, 10.1, 10.0, 9.7, 10.2
  • 机器B:10.0, 10.1, 10.2, 9.9, 10.3, 10.0, 9.8, 10.2, 10.1, 9.9

使用两样本K-S检验(α=0.05\alpha=0.05)判断两台机器生产的零件直径分布是否相同。

参考答案: ```python machine_a = np.array([10.1, 10.3, 9.8, 10.0, 10.2, 9.9, 10.1, 10.0, 9.7, 10.2]) machine_b = np.array([10.0, 10.1, 10.2, 9.9, 10.3, 10.0, 9.8, 10.2, 10.1, 9.9])

# 两样本K-S检验
stat, p = stats.ks_2samp(machine_a, machine_b)

print(f"两样本K-S统计量: {stat:.4f}")
print(f"P值: {p:.4f}")

if p < 0.05:
    print("拒绝H0,两台机器生产的零件直径分布不同。")
else:
    print("不拒绝H0,两台机器生产的零件直径分布无显著差异。")
```

本章小结

本节深入讲解了Kolmogorov检验的原理与应用,以下是核心要点回顾:

要点回顾

  1. 检验目标:判断样本是否来自一个完全已知的连续型分布
  2. 核心工具:基于经验分布函数Fn(x)F_n(x)与理论分布函数F0(x)F_0(x)最大绝对偏差DnD_n构造检验统计量。
  3. 检验决策:当DnD_n过大(超过临界值或p值过小)时,拒绝“样本来自F0(x)F_0(x)”的原假设。
  4. 分布理论DnD_n的精确分布复杂,但大样本下有Kolmogorov渐近分布K(λ)K(\lambda)
  5. 实践工具:Python的SciPy库提供了kstest函数,可方便地进行单样本和两样本K-S检验。

行动清单

  1. 掌握适用条件:面对分布检验问题时,首先判断F0(x)F_0(x)是否连续且完全已知,以决定是否适用K-S检验。
  2. 学会Python实现:熟练使用scipy.stats.kstestscipy.stats.ks_2samp函数进行单样本和两样本检验。
  3. 理解检验逻辑:不仅能运行代码,更要理解K-S统计量DnD_n的几何意义——它是两个分布函数曲线之间的最大垂直距离。
  4. 对比方法优劣:明确K-S检验与卡方拟合优度检验的适用场景,在实际问题中选择合适的方法。

Kolmogorov检验以其直观的几何解释和对小样本的适用性,成为分布检验中的重要工具。然而,务必牢记其核心限制:要求理论分布完全已知且连续。当分布含有未知参数时,需要考虑使用修正的K-S检验或其他方法。

— 小象教研组

配套学习资源与课件
  • 第5章课件:分布的检验(PDF · 3.8MB)
    下载
🎁 免费学习资源

领取《小象 11GB VIP 课件资料包与大厂真题手册》

包含全套实战 Jupyter 源码、清洗后数据集、大厂高频面试真题与专属学员答疑交流群。

  • 完整 Python / 数据分析 Jupyter 实战源码
  • 大厂真实业务数据集与练习题
  • 微信扫码添加课程顾问,免费获取网盘下载链接
微信二维码:扫码添加课程顾问微信扫码添加顾问