7.5 组间差异的非参数检验

如果数据无法满足t检验或ANOVA的参数假设,可以转而使用非参数方法。举例来说,若结果变量在本质上就严重偏倚或呈现有序关系,那么你可能会希望使用本节中的方法。

7.5.1 两组的比较

若两组数据独立,可以使用Wilcoxon秩和检验(更广为人知的名字是Mann–Whitney U检验)来评估观测是否是从相同的概率分布中抽得的(即,在一个总体中获得更高得分的概率是否比另一个总体要大)。调用格式为:

  1. wilcox.test(y ~ x, data)

其中的y是数值型变量,而x是一个二分变量。调用格式或为:

  1. wilcox.test(y1, y2)

其中的y1y2为各组的结果变量。可选参数data的取值为一个包含了这些变量的矩阵或数据框。默认进行一个双侧检验。你可以添加参数exact来进行精确检验,指定alternative="less"alternative="greater"进行有方向的检验。

如果你使用Mann–Whitney U检验回答上一节中关于监禁率的问题,将得到这些结果:

  1. > with(UScrime, by(Prob, So, median))
  2. So: 0
  3. [1] 0.0382
  4. --------------------
  5. So: 1
  6. [1] 0.0556
  7. > wilcox.test(Prob ~ So, data=UScrime)
  8. Wilcoxon rank sum test
  9. data: Prob by So
  10. W = 81, p-value = 8.488e-05
  11. alternative hypothesis: true location shift is not equal to 0

你可以再次拒绝南方各州和非南方各州监禁率相同的假设(p < 0.001)。

Wilcoxon符号秩检验是非独立样本t检验的一种非参数替代方法。它适用于两组成对数据和无法保证正态性假设的情境。调用格式与Mann–Whitney U检验完全相同,不过还可以添加参数paired=TRUE。让我们用它解答上一节中的失业率问题:

  1. > sapply(UScrime[c("U1","U2")], median)
  2. U1 U2
  3. 92 34
  4. > with(UScrime, wilcox.test(U1, U2, paired=TRUE))
  5. Wilcoxon signed rank test with continuity correction
  6. data: U1 and U2
  7. V = 1128, p-value = 2.464e-09
  8. alternative hypothesis: true location shift is not equal to 0

你再次得到了与配对t检验相同的结论。

在本例中,含参的t检验和与其作用相同的非参数检验得到了相同的结论。当t检验的假设合理时,参数检验的功效更强(更容易发现存在的差异)。而非参数检验在假设非常不合理时(如对于等级有序数据)更适用。

7.5.2 多于两组的比较

在要比较的组数多于两个时,必须转而寻求其他方法。考虑7.4节中的state.x77数据集。它包含了美国各州的人口、收入、文盲率、预期寿命、谋杀率和高中毕业率数据。如果你想比较美国四个地区(东北部、南部、中北部和西部)的文盲率,应该怎么做呢?这称为单向设计(one-way design),我们可以使用参数或非参数的方法来解决这个问题。

如果无法满足ANOVA设计的假设,那么可以使用非参数方法来评估组间的差异。如果各组独立,则Kruskal—Wallis检验将是一种实用的方法。如果各组不独立(如重复测量设计或随机区组设计),那么Friedman检验会更合适。

Kruskal–Wallis检验的调用格式为:

  1. kruskal.test(y ~ A, data)

其中的y是一个数值型结果变量,A是一个拥有两个或更多水平的分组变量(grouping variable)。(若有两个水平,则它与Mann–Whitney U检验等价。)而Friedman检验的调用格式为:

  1. friedman.test(y ~ A | B, data)

其中的y是数值型结果变量,A是一个分组变量,而B是一个用以认定匹配观测的区组变量(blocking variable)。在以上两例中,data皆为可选参数,它指定了包含这些变量的矩阵或数据框。

让我们利用Kruskal–Wallis检验回答文盲率的问题。首先,你必须将地区的名称添加到数据集中。这些信息包含在随R基础安装分发的state.region数据集中。

  1. states <- as.data.frame(cbind(state.region, state.x77))

现在就可以进行检验了:

  1. > kruskal.test(Illiteracy ~ state.region, data=states)
  2. Kruskal-Wallis rank sum test
  3. data: states$Illiteracy by states$state.region
  4. Kruskal-Wallis chi-squared = 22.7, df = 3, p-value = 4.726e-05

显著性检验的结果意味着美国四个地区的文盲率各不相同(p <0.001)。

虽然你可以拒绝不存在差异的原假设,但这个检验并没有告诉你哪些地区显著地与其他地区不同。要回答这个问题,你可以使用Mann–Whitney U检验每次比较两组数据。一种更为优雅的方法是在控制犯第一类错误的概率(发现一个事实上并不存在的差异的概率)的前提下,执行可以同步进行的多组比较,这样可以直接完成所有组之间的成对比较。npmc包提供了所需要的非参数多组比较程序。

说实话,我将本章标题中基本的定义拓展了不止一点点,但由于在这里讲非常合适,所以希望你能够容忍我的做法。第一步,请先安装npmc包。此包中的npmc()函数接受的输入为一个两列的数据框,其中一列名为var(因变量),另一列名为class(分组变量)。代码清单7-20中包含了可以用来完成计算的代码。

代码清单7-20 非参数多组比较

  1. > class <- state.region
  2. > var <- state.x77[,c("Illiteracy")]
  3. > mydata <- as.data.frame(cbind(class, var))
  4. > rm(class, var)
  5. > library(npmc)
  6. > summary(npmc(mydata), type="BF")
  7. $'Data-structure'
  8. group.index class.level nobs
  9. Northeast 1 Northeast 9
  10. South 2 South 16
  11. North Central 3 North Central 12
  12. West 4 West 13
  13. $'Results of the multiple Behrens-Fisher-Test' # ❶ 成对组间比较结果
  14. cmp effect lower.cl upper.cl p.value.1s p.value.2s
  15. 1 1-2 0.8750 0.66149 1.0885 0.000665 0.00135
  16. 2 1-3 0.1898 -0.13797 0.5176 0.999999 0.06547
  17. 3 1-4 0.3974 -0.00554 0.8004 0.998030 0.92004
  18. 4 2-3 0.0104 -0.02060 0.0414 1.000000 0.00000
  19. 5 2-4 0.1875 -0.07923 0.4542 1.000000 0.02113
  20. 6 3-4 0.5641 0.18740 0.9408 0.797198 0.98430
  21. > aggregate(mydata, by=list(mydata$class), median) # ❷ 各类别的文盲率中间值
  22. Group.1 class var
  23. 1 1 1 1.10
  24. 2 2 2 1.75
  25. 3 3 3 0.70
  26. 4 4 4 0.60

调用了npmc的语句生成了六对统计比较结果(东北部对南部、东北部对中北部、东北部对西部、南部对中北部、南部对西部,以及中北部对西部)❶。可以从双侧的p值(p.value.2s)看出南部与其他三个地区显著不同,而其他三个地区之间并没有什么不同。在❷处可以看到南部的文盲率中间值更高。注意,npmc在计算积分时使用了随机数,所以每次计算的结果会有轻微的不同。