对 95% 置信区间的重复实验解释的模拟研究存在问题 - 我哪里出错了?

机器算法验证 r 置信区间 二项分布 数理统计
2022-03-13 16:18:04

我正在尝试编写一个 R 脚本来模拟 95% 置信区间的重复实验解释。我发现它高估了一个比例的真实总体值包含在样本的 95% CI 内的次数比例。差别不大——大约 96% 和 95%,但这仍然让我感兴趣。

我的函数samp_n从具有概率 的伯努利分布中抽取样本pop_p,然后prop.test()使用连续性校正或更准确地使用 来计算 95% 的置信区间binom.test()如果真实人口比例pop_p包含在 95% CI 内,则返回 1。我写了两个函数,一个使用prop.test(),一个使用binom.test(),并且两者都有相似的结果:

in_conf_int_normal <- function(pop_p = 0.3, samp_n = 1000, correct = T){
    ## uses normal approximation to calculate confidence interval
    ## returns 1 if the CI contain the pop proportion
    ## returns 0 otherwise
    samp <- rbinom(samp_n, 1, pop_p)
    pt_result <- prop.test(length(which(samp == 1)), samp_n)
    lb <- pt_result$conf.int[1]
        ub <- pt_result$conf.int[2]
    if(pop_p < ub & pop_p > lb){
        return(1)
    } else {
    return(0)
    }
}
in_conf_int_binom <- function(pop_p = 0.3, samp_n = 1000, correct = T){
    ## uses Clopper and Pearson method
    ## returns 1 if the CI contain the pop proportion
    ## returns 0 otherwise
    samp <- rbinom(samp_n, 1, pop_p)
    pt_result <- binom.test(length(which(samp == 1)), samp_n)
    lb <- pt_result$conf.int[1]
        ub <- pt_result$conf.int[2] 
    if(pop_p < ub & pop_p > lb){
        return(1)
    } else {
    return(0)
    }
 }

我发现,当你重复实验几千次时,pop_p样本的 95% CI 内的次数比例更接近于 0.96 而不是 0.95。

set.seed(1234)
times = 10000
results <- replicate(times, in_conf_int_binom())
sum(results) / times
[1] 0.9562

到目前为止,我对为什么会这样的想法是

  • 我的代码是错误的(但我已经检查了很多)
  • 我最初认为这是由于正常的近似问题,但后来发现binom.test()

有什么建议么?

1个回答

你不会错的。由于结果的离散性,不可能为始终准确覆盖95%的二项式比例构建置信区间Clopper-Pearson(“精确”)区间保证覆盖率至少为95%。当对真实比例进行平均时,其他区间的平均覆盖率接近 95% 。

我自己倾向于使用 Jeffreys 区间,因为它的平均覆盖率接近 95%,并且(与 Wilson 得分区间不同)两条尾部的覆盖率大致相等。

只需对问题中的代码进行少量更改,我们就可以在没有模拟的情况下计算准确的覆盖率。

p <- 0.3
n <- 1000

# Normal test
CI <- sapply(0:n, function(m) prop.test(m,n)$conf.int[1:2])
caught.you <- which(CI[1,] <= p & p <= CI[2,])
coverage.pr <- sum(dbinom(caught.you - 1, n, p))

# Clopper-Pearson
CI <- sapply(0:n, function(m) binom.test(m,n)$conf.int[1:2])
caught.you.again <- which(CI[1,] <= p & p <= CI[2,])
coverage.cp <- sum(dbinom(caught.you.again - 1, n, p))

这会产生以下输出。

> coverage.pr
[1] 0.9508569

> coverage.cp
[1] 0.9546087