Fisher精确检验(Fisher’s Exact Test)

适用于分析2×2列联表(如治疗 vs. 不治疗,生存 vs. 死亡),特别适用于小样本数据(如某些单元格期望计数 <5)。

生存死亡总计
治疗组8210
对照组3710
总计11920

2. Fisher检验的原假设(H₀)

H₀:治疗与生存率无关(即治疗对生存率无影响)。
换句话说,治疗组和对照组的生存/死亡比例来自同一个总体分布。


3. 抽球原理类比

  • 想象一个袋子中有 20个球(代表所有受试者):
    • 11个白球(生存)
    • 9个黑球(死亡)
  • 随机抽取10个球(治疗组),剩下的10个是对照组。
  • 问题:如果治疗无效,治疗组中抽到8个白球(生存)的概率是多少?

Fisher检验的核心

计算在H₀成立时,观察到当前表格(或更极端情况)的超几何概率:

(即治疗组生存数≥8的概率)


4. R语言实现

# 构造列联表
data <- matrix(c(8, 2, 3, 7), nrow = 2, byrow = TRUE)
rownames(data) <- c("治疗组", "对照组")
colnames(data) <- c("生存", "死亡")
 
# Fisher精确检验
fisher.test(data)

输出结果

p-value = 0.0345
alternative hypothesis: true odds ratio is not equal to 1
  • p值=0.0345(<0.05),拒绝H₀,说明治疗与生存率显著相关。

  • 显著性:p值<0.05,表明治疗组和对照组的生存率差异非随机产生。
  • 方向性:治疗组生存率(8/10=80%)高于对照组(3/10=30%)。
  • 优势比(Odds Ratio):

    治疗组的死亡风险是对照组的1/9.33≈0.11倍(保护效应)。

  • H₀:治疗与生存无关(两组生存率相同)。
  • 检验原理:通过超几何分布计算极端情况的概率。
  • 适用场景:小样本、2×2列联表,尤其当卡方检验不满足条件时。
  • 结论:本例中治疗显著提高生存率(p=0.0345)。

列联表行/列转置是否影响Fisher检验结果?

1. 转置后的列联表

原始表(生存/死亡在列):

生存死亡总计
治疗组8210
对照组3710
总计11920

转置后(生存/死亡在行):

治疗组对照组总计
生存8311
死亡279
总计101020

2. Fisher检验的数学本质

  • 检验的假设(H₀)不变:

    • 原假设始终是行变量与列变量独立(如治疗与生存无关)。
    • 转置仅改变表格的展示方式,不改变变量间的关系。
  • 统计量计算不受影响:
    Fisher检验基于超几何分布,其概率公式为:

    其中 是四格表的单元格值, 是总样本量。
    转置后,单元格的数学关系保持不变(如原始表的 仍是转置后的 )。

3. R语言验证

# 原始表(生存/死亡在列)
data_original <- matrix(c(8, 2, 3, 7), nrow = 2, byrow = TRUE)
fisher.test(data_original)$p.value  # 输出: 0.0345
 
# 转置后(生存/死亡在行)
data_transposed <- t(data_original)
fisher.test(data_transposed)$p.value  # 输出: 0.0345

结果一致,p值均为0.0345。

4. 解释的侧重点差异

虽然统计结论相同,但转置可能影响结果表述的侧重点:

  • 原始表:
    • 解释为“治疗组的生存率是否显著高于对照组”。
  • 转置表:
    • 解释为“生存组的治疗比例是否显著高于死亡组”。

Q1: alternative = "less" 是否计算 4/3/2…个球的概率?

  • 是。
    • 如果当前抽到 5 个白球,less 计算的是抽到 ≤5 个白球的概率(即 0,1,2,3,4,5)。
    • 但若当前观察值已在左侧(如 2 个白球),less 会计算更小值(0,1,2)。

Q2: alternative = "greater" 是否计算 5/6/7…个球的概率?

  • 是。
    • 如果当前抽到 5 个白球,greater 计算的是抽到 ≥5 个白球的概率(即 5,6,7,…)。

Q3: two.sided(双尾)的计算逻辑?

  • 不是简单的左尾+右尾,而是:
    • 计算所有与当前表格或更极端情况的概率(按优势比定义极端性)。
    • 例如:若当前表格的 OR=4,则双尾 p值包括所有 OR≥4 或 OR≤1/4 的表格概率之和。

4. R代码验证

data <- matrix(c(8, 2, 3, 7), nrow = 2)
 
# 右尾检验(治疗组生存率 > 对照组)
fisher.test(data, alternative = "greater")$p.value  # 输出: 0.017
 
# 左尾检验(治疗组生存率 < 对照组)
fisher.test(data, alternative = "less")$p.value    # 输出: 0.99
 
# 双尾检验(默认)
fisher.test(data, alternative = "two.sided")$p.value  # 输出: 0.0345

核心要点

  1. 单尾检验需预先指定方向,不可根据数据结果事后选择。
  2. 双尾检验是默认选择,除非有强理论支持单侧假设。
  3. Fisher检验的 p值基于超几何分布的极端概率累加。
  • 总球数
  • 成功球(标记为“白球”)数
  • 失败球(“黑球”)数
  • 抽取数

假设你观察到抽到 个成功球。


2. 超几何概率分布(抽出成功球数的概率)

公式:

我们先计算所有可能的 的概率:

x(成功数)012345678910
P(X=x)0.00020.00210.01130.03910.09160.15010.18810.16860.10480.03630.0080

3. 各种 alternative 计算的 p 值区域

假设观察到 :

  • “less”:计算
  • “greater”:计算
  • “two.sided”:计算所有概率 ≤ 的概率和

4. 哪些值“更极端”?

  • 找所有 使得 ,包括 (因为 , 都大于 0.1501)

所以,


# 原始列联表(治疗为行,生存和死亡为列)
#       生存  死亡
# 治疗    8     2
# 未治疗  4     6
 
table_orig <- matrix(c(8, 2, 4, 6), nrow=2, byrow=F)
rownames(table_orig) <- c("治疗", "未治疗")
colnames(table_orig) <- c("生存", "死亡")
print("原始列联表:")
print(table_orig)
 
# Fisher检验 alternative = "greater"  # 检验治疗组“生存”数量更多
res_orig_greater <- fisher.test(table_orig, alternative = "greater")
print("原始表 alternative = 'greater' (治疗组生存数更多):")
print(res_orig_greater$p.value)
 
# Fisher检验 alternative = "less"  # 检验治疗组“生存”数量更少
res_orig_less <- fisher.test(table_orig, alternative = "less")
print("原始表 alternative = 'less' (治疗组生存数更少):")
print(res_orig_less$p.value)
 
 
# 交换“生存”和“死亡”两列,列顺序变为死亡-生存
table_swap <- table_orig[, c("死亡", "生存")]
print("交换列后列联表(死亡和生存列顺序交换):")
print(table_swap)
 
# 这时如果仍用 alternative = "greater",其实检验的是治疗组“死亡”数量是否更多
res_swap_greater <- fisher.test(table_swap, alternative = "greater")
print("交换列后 alternative = 'greater' (治疗组死亡数更多):")
print(res_swap_greater$p.value)
 
# alternative = "less" 检验治疗组“死亡”数量是否更少
res_swap_less <- fisher.test(table_swap, alternative = "less")
print("交换列后 alternative = 'less' (治疗组死亡数更少):")
print(res_swap_less$p.value)