如何用R/Python实现Kolmogorov-Smirnov检验功效的蒙特卡洛模拟
KS检验与Lilliefors检验功效蒙特卡洛模拟复现方案
首先明确两个检验的核心差异,避免复现逻辑出错:
- 普通Kolmogorov-Smirnov(KS)检验:原假设下分布完全已知(本次设定为固定的标准正态$N(0,1)$,无参数估计步骤),临界值直接调用
scipy.stats.ksone计算,完全匹配原论文的实现逻辑 - Lilliefors检验:正态分布拟合优度场景下的KS修正版本,原假设为样本来自某一正态分布(均值、方差由样本估计,不固定为0和1),临界值不能直接套用ksone分布,需使用Lilliefors专属临界值计算结果
模拟参数对齐原论文设定
- 显著性水平$\alpha=0.05$
- 固定样本量$n=100$
- 备择真实分布:$Beta(2,2)$
- 功效计算逻辑:重复生成指定分布的样本、执行检验,统计拒绝原假设的次数占总重复次数的比例
- 建议模拟重复次数:至少10000次,结果波动可控制在1%以内
Python实现代码(对齐原论文scipy实现逻辑)
先安装依赖:pip install numpy scipy statsmodels matplotlib
import numpy as np from scipy import stats from statsmodels.stats.diagnostic import lilliefors import matplotlib.pyplot as plt # 固定随机种子保证结果可复现 np.random.seed(42) # 初始化模拟参数 alpha = 0.05 n = 100 n_reps = 10000 # 普通KS检验临界值,直接调用原论文提及的scipy.stats.ksone模块计算 ks_critical = stats.ksone.ppf(1 - alpha, n) # 拒绝次数计数 ks_reject = 0 lillie_reject = 0 for _ in range(n_reps): # 生成Beta(2,2)分布样本,值域为[0,1]无需额外转换 sample = np.random.beta(2, 2, size=n) # 1. 普通KS检验:原假设为样本来自固定的N(0,1) ks_stat, _ = stats.kstest(sample, cdf='norm', args=(0,1)) if ks_stat > ks_critical: ks_reject += 1 # 2. Lilliefors检验:原假设为样本来自某正态分布(参数从样本估计) # statsmodels内置临界值与原论文使用的Lilliefors临界值表一致 lillie_stat, lillie_p = lilliefors(sample, dist='norm') if lillie_p < alpha: lillie_reject +=1 # 计算检验功效 ks_power = ks_reject / n_reps lillie_power = lillie_reject / n_reps print(f"普通KS检验(F0固定为N(0,1))功效:{ks_power:.3f}") print(f"Lilliefors检验功效:{lillie_power:.3f}") # 绘制结果对比图 plt.figure(figsize=(6,4)) tests = ['Kolmogorov-Smirnov', 'Lilliefors'] powers = [ks_power, lillie_power] bars = plt.bar(tests, powers, color=['#1f77b4', '#ff7f0e']) plt.ylabel('检验功效(α=0.05, n=100, 真实分布Beta(2,2))') plt.ylim(0, 1) # 柱子上标注功效数值 for bar in bars: height = bar.get_height() plt.text(bar.get_x() + bar.get_width()/2., height, f'{height:.3f}', ha='center', va='bottom') plt.tight_layout() plt.show()
结果说明:Beta(2,2)均值为0.5、方差为0.05,和固定的N(0,1)位置、尺度差异极大,因此固定参数的普通KS检验功效会接近1;而Lilliefors检验允许正态分布的均值、方差从样本估计,仅检验分布形态是否符合正态,Beta(2,2)为对称有界分布,和正态的形态差异远小于位置尺度差异,因此功效会显著低于普通KS检验,和原论文结果趋势完全一致。
R可选实现方案
核心逻辑与Python版本一致,代码如下:
set.seed(42) # 加载Lilliefors检验所需包,首次运行请先执行install.packages("nortest") library(nortest) alpha <- 0.05 n <- 100 n_reps <- 10000 ks_reject <- 0 lillie_reject <- 0 for (i in 1:n_reps) { sample <- rbeta(n, 2, 2) # 普通KS检验,固定原分布为N(0,1) ks_res <- ks.test(sample, "pnorm", 0, 1) if (ks_res$p.value < alpha) ks_reject <- ks_reject + 1 # Lilliefors检验 lillie_res <- lillie.test(sample) if (lillie_res$p.value < alpha) lillie_reject <- lillie_reject + 1 } ks_power <- ks_reject / n_reps lillie_power <- lillie_reject / n_reps print(paste0("KS检验功效:", round(ks_power,3))) print(paste0("Lilliefors检验功效:", round(lillie_power,3))) # 绘制对比图 barplot(c(ks_power, lillie_power), names.arg = c("Kolmogorov-Smirnov", "Lilliefors"), ylab = "检验功效", ylim = c(0,1), col = c("#1f77b4", "#ff7f0e"))
内容的提问来源于stack exchange,提问作者oliver
相关产品推荐
相关产品推荐

