跳到正文
百沐一下百沐一下
本节目录

方差分析与事后多重比较

跟完这篇,您能对三组及以上的数据做单因素与双因素方差分析(ANOVA),读懂交互作用,在 Tukey 与 Dunnett 之间选对事后比较,并在前提不满足时换用 Kruskal-Wallis——每一步都有可照着敲的 R 代码。

比较两组差异用 t 检验;一旦到了三组及以上,就该用方差分析。有人图省事,把多组拆成好几次两两 t 检验——这会放大假阳性(原因见 多重检验校正)。正确顺序是两步:先用 ANOVA 做一次整体检验,回答「这几组之间到底有没有差异」;整体显著后,再用事后比较定位「具体是哪几组不同」,并对多重比较做校正。这篇就带您把这条链完整走一遍。

什么时候用方差分析

方差分析回答的是一个整体问题:若干组的均值是不是全都相等? 原假设是「各组均值相等」,p 小则提示「至少有一组和别人不一样」——但它不会告诉您是哪一组,这要留给事后比较。

按您手头的设计,对应不同版本:

场景方法例子
一个分组因素、三组及以上单因素 ANOVA比较对照、低剂量、高剂量三组的表达量
两个分组因素双因素 ANOVA同时看「饮食」和「性别」对体重的影响,以及两者是否相互作用
不满足正态、或有难处理的离群值Kruskal-Wallis(非参数)小样本、明显偏态时替代单因素 ANOVA

开工前先把数据摆成长表,这是 R 里做 ANOVA 最顺手的格式:

  1. 每行一个样本(观测);
  2. 一列放要比较的数值(因变量,连续型);
  3. 一列或多列放分组(自变量),且必须是因子(factor)类型。
str(df)
# 分组列若还是字符或数字,先转成因子,R 才会当成「类别」而非数值处理
df$group <- as.factor(df$group)

分组列忘了转因子,是新手最常见的坑:R 会把 1/2/3 当连续变量去拟合,结果完全跑偏。

单因素 ANOVA:一步步做

以「一个分组因素、三组」为例,照着走:

  1. 拟合模型。公式写成 数值 ~ 分组

    fit <- aov(value ~ group, data = df)
    
  2. 看整体检验结果

    summary(fit)
    

    输出是一张方差分析表,重点看 group 这一行的最后一列 Pr(>F)

    含义
    Df自由度
    Sum Sq / Mean Sq离差平方和 / 均方
    F valueF 统计量:组间变异相对组内变异有多大
    Pr(>F)对应的 p 值——这就是整体检验的结论
  3. 判断group 行的 Pr(>F) < 0.05,说明各组均值不全相等,可以进入下一步的事后比较;若不显著,通常就停在这里,不必再两两比。

p < 0.05 判显著是常用惯例、不是铁律,请结合效应量、样本量和研究场景一起判断。

只报一个 p 值往往不够。按惯例还应给出效应量,说明差异有多大而不只是「显著与否」,方差分析里常用 η²(eta-squared):

# 需要 effectsize 包;报告效应量是良好习惯,别只交代 p 值
library(effectsize)
eta_squared(fit)

检查前提假设

ANOVA 和 t 检验一样有三条前提:观测独立、残差近似正态、各组方差齐。前两条里「独立」由实验设计决定、数据补不回来;正态和方差齐则有一定容忍度,样本量大且各组均衡时更稳健。拟合完模型后,按下面顺序核对:

  1. 残差正态性。注意看的是模型残差,不是原始数据:

    qqnorm(residuals(fit)); qqline(residuals(fit))   # 点大致沿直线即可
    shapiro.test(residuals(fit))                     # 辅助检验,别只看它
    

    shapiro.testp 别当开关用:小样本检验力弱、大样本又会对无关紧要的微小偏离过度敏感,配合 Q-Q 图一起看更靠谱。

  2. 方差齐性。常用 Levene 检验,它比 Bartlett 对正态偏离更稳健:

    library(car)
    leveneTest(value ~ group, data = df)   # p < 0.05 提示方差不齐
    plot(fit, 1)                           # 残差 vs 拟合值,看散布是否随组变化
    
  3. 方差不齐怎么办。改用不要求方差齐的 Welch 方差分析

    oneway.test(value ~ group, data = df, var.equal = FALSE)   # Welch ANOVA
    

    这一步和 t 检验里「方差不齐就用 Welch t」是一个道理。方差不齐时,事后比较也要换成对应的稳健方法(见下一节的 Games-Howell)。

事后多重比较:Tukey 还是 Dunnett

ANOVA 整体显著后,事后比较负责回答「具体哪几组不同」。它们都会内建多重比较校正,这正是不能用裸奔的两两 t 检验的原因。选哪种,取决于您真正关心哪些对比:

场景事后方法R 写法
想两两全比(每组对每组)Tukey HSDTukeyHSD(fit)
各处理组只跟一个对照Dunnettmultcomp::glht(...)
方差不齐Games-Howellrstatix::games_howell_test()

Tukey HSD:给出所有两两组合的差值、置信区间和校正后 p 值,适合「没有预设方向,想全面看看谁和谁不同」:

TukeyHSD(fit)
plot(TukeyHSD(fit))   # 置信区间不跨 0 的那对,即为显著

Dunnett:只把每个处理组跟指定的对照组比(如「各给药组 vs 安慰剂」)。因为对比数量更少,检验力通常高于 Tukey——只要您的问题确实是「和对照差不差」,就优先它:

library(multcomp)
# 确保对照是因子的第一个水平;relevel 可指定谁当参照
df$group <- relevel(df$group, ref = "control")
fit <- aov(value ~ group, data = df)

dunnett <- glht(fit, linfct = mcp(group = "Dunnett"))
summary(dunnett)   # 每个处理组与对照的比较,已做多重校正

一句话选法:想两两全比,用 Tukey;只关心「各组 vs 一个对照」,用 Dunnett(更省、更有力);方差明显不齐,用 Games-Howell。

双因素 ANOVA 与交互作用

当有两个分组因素时(如「饮食」×「性别」),双因素 ANOVA 能一次回答三个问题:饮食有没有主效应、性别有没有主效应、以及两者是否存在交互作用

  1. 拟合模型。用 * 连接两个因素,它会自动展开成「两个主效应 + 交互项」:

    fit2 <- aov(value ~ diet * sex, data = df)
    # 等价于 value ~ diet + sex + diet:sex
    summary(fit2)
    
  2. 先看交互项diet:sex 这一行)。交互作用的含义是:一个因素的效应,会随另一个因素的水平而改变。

    • 交互项显著 → 别再孤立地解读主效应,因为「饮食的作用」在不同性别下并不一样,笼统说「饮食有没有效」会误导。此时应看简单效应(固定一个因素,在其每个水平内分别比较另一个因素)。
    • 交互项不显著 → 可以放心分别解读两个主效应。
  3. 画交互作用图帮助判断:

    interaction.plot(df$diet, df$sex, df$value)
    

    两条线大致平行,提示没有交互作用;线明显交叉或发散,提示有交互作用。

  4. 交互显著时,拆简单效应emmeans 包很适合做这件事:

    library(emmeans)
    # 在每个性别内,分别比较不同饮食(并自动做多重校正)
    emmeans(fit2, pairwise ~ diet | sex)
    

一个容易被忽略的细节:当各组样本量不相等(不平衡设计)时,aov() 默认的 I 型平方和会受因素书写顺序影响。此时按惯例常改用 II 型或 III 型平方和,例如 car::Anova(fit2, type = 2)。平衡设计下三者结果一致,无需纠结。

非参数替代:Kruskal-Wallis

如果是小样本又明显偏离正态、或有难以处理的离群值,就把单因素 ANOVA 换成它的非参数对应——Kruskal-Wallis 检验。它比较的是各组的秩分布,不要求正态:

kruskal.test(value ~ group, data = df)   # p 小提示各组分布不全相同

整体显著后,同样需要事后两两比较。两种常规做法:

# 做法一:Dunn 检验,KW 之后最常配套的事后方法(需 FSA 包)
library(FSA)
dunnTest(value ~ group, data = df, method = "bh")   # bh:Benjamini-Hochberg 校正

# 做法二:成对 Wilcoxon 秩和检验,并对多重比较做校正
pairwise.wilcox.test(df$value, df$group, p.adjust.method = "BH")

用非参数方法时,有两点边界要心里有数:

  • Kruskal-Wallis 只处理一个分组因素,没有直接对应「双因素 + 交互」的标准方法。两因素又严重非正态时,常见做法是先尝试变量变换(如对数),或改用更专门的稳健模型;
  • 当数据其实近似正态时,非参数方法的效能通常略低于 ANOVA。所以不是「拿不准就一律非参数」,而是「ANOVA 前提明显不满足时才换」。

到这里,一条完整的分析链就走通了:分清几个因素 → 拟合 ANOVA、看整体是否显著 → 核对残差正态与方差齐(不满足就 Welch 或 Kruskal-Wallis)→ 按「两两全比 or 对照比」选 Tukey 或 Dunnett 做事后比较 → 双因素别忘了先看交互作用。

在平台上跑一遍

上面这套流程您不必手动敲代码。在百沐一下的【智能统计】里,上传一张整洁的长表(每行一个样本、含分组列),用一句话说清目的,例如「比较三组表达量是否有显著差异,并两两比较」,它会自动帮您核对正态与方差齐性、选好 ANOVA 或 Kruskal-Wallis、跑出整体检验与事后比较,并附上可复现的 R 代码供您核对。用法见 智能统计使用指南,或直接登录 app.baimuyixia.com 试一遍。

相关