为什么我的 Fisher 检验“显着”但优势比重叠 1?

机器算法验证 置信区间 优势比 渔民精确测试
2022-04-18 08:43:48

给定以下罕见事件的列联表,为什么我的 Fisher 精确检验会产生“显着值”(即 < 0.05)但也显示 OR 的置信区间与 1 重叠?我的理解是,一个显着的值应该表明 OR 为 1 被排除在 95% CI 之外。p值是否单向,因此需要解释为 2 x p (0.0573)?

        FALSE TRUE
  FALSE  3200    6
  TRUE    885    6

    Fisher's Exact Test for Count Data

data:  table
p-value = 0.02865
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
  0.9636962 13.5569691
sample estimates:
odds ratio 
  3.613991 
1个回答

这是一个有趣的现象。

区别基本上在于零假设更强大,因为它最终是片面的。置信区间不是基于相同的强大测试(但它可以)。

用左右尾的可变权重检验零假设

请注意,单元格 1,1 中值的概率(我们称之为x)仅基于左尾的 p 值为 0.028 (值 3200 及以上的概率总和)。此示例中没有右尾,因为该值不能低于 3194。

超几何分布

置信区间假设尾部相等的双边检验

置信区间是根据Fisher 的非中心超几何分布计算的。区间下限是基于比值比的值,其观察概率x3200为 0.025 或更小。

这个值恰好低于1。这并不奇怪,因为我们计算出赔率 1 的概率为 0.028。

确定下置信边界

区别

因此我们可以说:不同之处在于,置信区间的计算是基于具有相等权重的两条尾部的假设检验。但用于计算 p 值的假设检验并非如此。

零假设的显着性检验将使用设定值±离最大似然估计有一定的距离。这可能不需要是两条相等的尾巴。

在此示例中,最大似然估计值为 3196。因此 p 值基于观察到的概率x3200或者x3192. 由于不对称,这条下尾巴不存在。

但是,置信区间的计算使用两个尾部具有相同权重的检验。

R代码

下面是一些可能有助于手动计算置信区间和 p 值的 r 代码,这可能有助于更深入地了解fisher.test函数。该代码是fisher.test函数底层代码的简化版本。

### data
mat <- matrix(c(3200,6,885,6),2, byrow = T)

### parameters describing the data
x <- c(3194:3206)   ### possible values for cell 1,1
m <- 3200+6    ### sum of row 1
n <- 885+6     ### sum of row 2
k <- 3200+885  ### sum of column 1


### fisher test
test <- fisher.test(mat)
test

### manual computation of p-values
f <- dhyper(x,m,n,k)
plot(x,f)
pvalue <- sum(f[x >= 3200])

### compare p-values (gives the same)
pvalue
test$p.value


### non-central hypergemoetric distribution
### copied from fisher.test function in R
### greatly simplified for easier overview
logdc <- dhyper(x, m, n, k, log = TRUE)

### PDF
dnhyper <- function(ncp) {
  d <- logdc + log(ncp) * x
  d <- exp(d - max(d))        
  d / sum(d)
}


### CDF
pnhyper <- function(q, ncp = 1, uppertail = F) {
  if (uppertail) {
    sum(dnhyper(ncp)[x >= q])
  }
  else  {
    sum(dnhyper(ncp)[x <= q])
  }
}
pnhyper <- Vectorize(pnhyper)

### alpha level
alpha <- (1-0.95)/2

### compute upper and lower boundaries
x1 <- uniroot(function(t) pnhyper(3200, t) - alpha,
              c(0.5, 20))$root
x2 <- uniroot(function(t) pnhyper(3200, t, uppertail = T) - alpha,
              c(0.5, 20))$root

### plotting
t <- seq(0.2,20,0.001)
plot(t,pnhyper(3200,t, uppertail = T), log = "x", type = "l", xlim = c(0.20,20), ylab = "P(x => 3200)", xlab = "odds")
lines(c(10^-3,10^3), 0.025*c(1,1), col = 2)
lines(c(x2,x2),c(0,1), lty = 2)