非参数检验笔记

前言

非参数检验(non-parametric test)是相对于参数检验(parametric test)而言的。如果总体分布为已知的数学形式,用参数检验,反之用非参数检验。当总体分布不能由已知的数学形式表达,没有总体参数时,就无法用参数检验,两个或多个正态总体方差不等,也不能用t检验或F检验的参数检验。对于不满足参数检验条件的数据,一是进行变量变换,使其满足参数检验条件,另外就是用非参数检验。非参检验对总体分布不作严格假定,又称任意分布检验(distribution-free test),《医学统计学》(第三版,孙振球)书中采用的是秩转换的非参数检验,即将数值变量从小到大排列,再计算检验统计量。

非参数检验在总体分布未知时有很大的优越性,在分布未时,如果还假定总体诸如正态分布那样的已知分布,在进行统计推断时就可能产生错误。非参数检验总是比传统检验案例,但是在总体分布形式已经已知时,非参数检验就不如传统方法效率高,这是因为非参数方法利用的利息要少些。往往在传统方法可以拒绝零假设的情况下,非参数检验无法拒绝。用统计的术语来说,在总体分布已知时,传统方法有较大的功效(power),效率要高;但非参数统计在总体分布未知时,效率往往比假定了错误总体分布时的传统方法要高,有时候要高很多。

秩的概念

非参数检验中的秩(rank)是最常用的概念,秩就是该数据按照升序排列后,每个观测值的位置。例如我们有下面的数据(样本量为10),其中第一行为数据本身,第二行就是它们的秩,可以看出,3最小,秩为1,13其次,秩为2,而最大的是98,秩为10,我们使用rank(x)表示x的秩,通常也用Ri表示观测值$x_{i}$的秩,如下所示:

$x_{i}$ 98 67 63 3 38 16 21 53 13 81
$R_{i}=rank(x_{i})$ 10 8 7 1 5 3 4 6 2 9

非参数检验的原理

如果零假设中确定了一个中位数$M_{0}$,那么样本点应该以同样的概率出现在$M_{0}$的两边,也就是说,如果每个样本点送去零假设的中位数,那么得到的差值有些为正,有些为负,如果零假设正确,那么正负符号数目应该差不多,如果差得很多,这就意味着零假设有问题,可以拒绝零假设。这也就是所谓的符号检验(sign test)

这里没有涉及任何总体分布,在零假设下,样本点和$M_{0}$的差值中负号的个数(记为$S^-$)应该服从二项分布Bin(n,α),而正号的个数(记为$S^+$)䚱服从二项分布Bin(n,1-α),注意,对于已知对称的分布,由于中位数和均值相等,对中位数的检验等同于对均值的检验,我们通过一个例子来解释符号检验。

单样本的关于总体中位数的符号检验

案例A,质量监督部门对商店里出售的某厂家的西洋参片进行了抽查,对于25包写明为净重100g的西洋参片的称重结果如下所示:

mark

这里的总体分布未知(我们只是假设未知,其实它的分布是可以计算出来的),用M表示总体中位数,容易计算出,样本中位数为m=98.36,因为人们怀疑厂家包装的西洋参片分量。由于对于重量的总体分布不清楚,决定对其进行符号检验,需要的检验如下所示:

按照零假设,每个观测值(每包西洋参的净重)大于中位数$M_{0}=100$的概率和小于100的概率都是0.5,这应该服从二项分布Bin(25,0.5),容易计算出大于100的只有$S^+=8$,这样的参数为n=25,p=0.5的二项分布变量小于或等于8的概率为0.05388,这就是p值,历引,对于显著性水平α=0.05,根据这个符号检验,我们没有足够的证据拒绝零假设。在R中计算的过程如下所示:

1
2
3
4
5
6
7
8
> pbinom(8,25,0.5)
[1] 0.05387607
# 或者按另外一种方法:
> raw <-c(99.05,100.25,102.56,99.15,104.89,101.86,96.37,96.79,99.37,
+ 96.9,93.94,92.97,108.28,96.86,93.94,98.27,98.36,100.81,92.99,
+ 103.72,90.66,98.24,97.87,99.21,101.79)
> pbinom(length(raw[raw>=100]),25,0.5)
[1] 0.05387607

一般来说,根据样本中位数和零假设中的待检验总体中位数$M_{0}$的比较,我们的检验为下面三种形式之一(记样本中位数为m),如下所示:

mark

这里的关于中位数的符号检验概率,完全可以很容易地推广到关于总体α分位数的符号检验中,如果零假设中确定了一个α分位数$Q_{\alpha0}$

那么,样本点应该以概率α出现在$Q_{\alpha0}$的左边,或者以概率1-α出现在$Q_{\alpha0}$的右边,因此样本点减去$Q_{\alpha0}$差值中铅的个数(记为$S^-$)应该服从二项分布Bin(n,α),而正号的个数(记为$S^+$)应该服从二项分布Bin(n,1-α)。当α=0.5时,总体α分位数就是总体中位数。

单样本的关于对称总体中位数的Wilcoxon符号秩检验

前面的符号检验仅仅用了样本点和零假设的中位数或α分位数的差的符号,我们可以看到,检验的结果p值大于0.05,但是这种检验方法没有利用这些差的大小,下面介绍的Wilcoxn符号秩检验(Wilcoxon signed-rank test)把差的绝对值的秩分别按照不同的符号相加作为其检验统计量,这里把对总体唯一假定是总体具有对称分布,这种检验方法我们可以看到,它的功效要比前面介绍的高(计算出来的p值小于0.05)。

Wilcoxon符号秩检验原理

Wilcoxon符号秩检验的原理是这样的,假定$x_{1},x_{2},\cdots,x_{n}$为来自连续对称总体的一个样本,如果我们的假设检验问题的零假设为中位数(均值)$M=M_{0}$。那么,对于符号检验而言,只需计算$x_{i}-M_{0}(i=1,2,\cdots,n)$中有多少正负符号,即可利用二项分布的概率来计算p值。但对于Wilcoxon符号秩检验,则要把$|x_{i}-M_{0}|$排序,得到$|x_{i}-M_{0}|$的秩。然后把$x_{i}-M_{0}$的符号加到相应的秩上面。于是,就可以得到既带有正号的秩,又带有负号的秩,对带负号的秩的绝对值求和,即把满足$x_{i}-M_{0}<0$的$|x_{i}-M_{0}|$的秩求和,并用$W^+$表示。如果$M_{0}$的确是中位娄和,那么$W^-$和$W^+$应该大体上差不多。如果$W^-$或者$W^+$过大或过小,则应该怀疑中位数$M=M_{0}$的零假设。令$W=min(W^-,W^+)$,则当W太小时,应该拒绝零假设。这个W就是Wilcoxon符号秩检验统计量。

R中的非参数检验函数

在R中进行Wilcoxon检验的函数是wilcoxon.test,使用方法如下所示:

如果总体不服从正态分布,那么T检验就不再适用,此时我们可以利用非参数方法推断中位数。wilcoxon.test函数可实现符号秩检验,如下所示:

1
2
3
x <- rnorm(50,mean=10,sd=5)
wilcox.test(x,conf.int=T) #指定conf.int让函数返回中位数的置信区间
wilcox.test(x,mu=1) #指定mu让函数返回中位数为10的检验结果

结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
> wilcox.test(x,conf.int=T) #指定conf.int让函数返回中位数的置信区间
Wilcoxon signed rank test with continuity correction
data: x
V = 1271, p-value = 9.93e-10
alternative hypothesis: true location is not equal to 0
95 percent confidence interval:
9.31246 12.20277
sample estimates:
(pseudo)median
10.7765
> wilcox.test(x,mu=1) #指定mu让函数返回中位数为10的检验结果
Wilcoxon signed rank test with continuity correction
data: x
V = 1269, p-value = 1.121e-09
alternative hypothesis: true location is not equal to 1

单个样本Wilcoxon检验案例

案例A

现在我们再看一下前面的那个案例A,使用Wilcoxon检验来看一下,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
> raw <-c(99.05,100.25,102.56,99.15,104.89,101.86,96.37,96.79,99.37,
+ 96.9,93.94,92.97,108.28,96.86,93.94,98.27,98.36,100.81,92.99,
+ 103.72,90.66,98.24,97.87,99.21,101.79)
> wilcox.test(raw,mu=100,alternative = "less")
Wilcoxon signed rank test with continuity correction
data: raw
V = 100, p-value = 0.04763
alternative hypothesis: true location is less than 100
Warning message:
In wilcox.test.default(raw, mu = 100, alternative = "less") :
无法精確計算带连结的p值

案例B

现在再看一个案例B,下面是随机挑选了12袋包装上写的重量是15g的干酵母粉,并进行称重所得到的重量的数据,如下所示:

1
12.39,15.64,14,14.17,14.08,14.16,13.94,14.61,14.7,12.81,14.12,13.37

由于总体中位数是14.1,而零假设的总体均值是15,因此我们可以怀疑这种袋装酵母粉不够分量,相应的关于中位数的检验如下所示:

假定总体是对称分布的,因此可以应用Wilcoxon符号秩检验,如下所示:

1
2
3
4
5
6
7
8
> raw_b <- c(12.39,15.64,14,14.17,14.08,14.16,13.94,14.61,14.7,12.81,14.12,13.37)
> wilcox.test(raw_b,m=15,alternative = "less")
Wilcoxon signed rank test
data: raw_b
V = 3, p-value = 0.001221
alternative hypothesis: true location is less than 15

案例C

例8-2 已知某地正常人尿氟含量的中位数为45.30μmol/L 。今在该地某厂随机抽取12名工人,测得尿氟含量见表8-2第(1)栏。问该厂工人的尿氟含量是否高于当地正常人的尿氟含量?(《医学统计学》,第三版,孙振球,P134)

1
2
data82 <- c(44.21,45.30,46.39,49.47,51.05,53.16,53.26,54.37,57.16,67.37,71.05,87.37)
wilcox.test(data82-45.30)

结果如下所示:

1
2
3
4
5
6
7
> wilcox.test(data82-45.30)
Wilcoxon signed rank test with continuity correction
data: data82 - 45.3
V = 65, p-value = 0.005099
alternative hypothesis: true location is not equal to 0

这个结果与书上有出入,书中提到,p值是小于0.005,则R的计算出来是0.005099,小于0.05,但SPSS的计算结果与R一致。

两个独立样本Wilcoxon检验(Mann-Whitney U检验)

如果是比较两个正态总体均值,那么就是使用t检验(检验均值之差为$\mu_{1}-\mu_{2}$),如果不知道两组数据是否服从哪种特定的总体分布,我们就要考虑比较两组数据的中位数大小,我们需要的唯一定义就是两个总体的分布有类似的形状,但不要求对称。这里介绍的检验的原理很简单,假定第一个样本有m个观测值$x_{1},\cdots,x_{m}$,第二个有n个观测值,$y_{1},\cdots,y_{n}$。把两个样本混合之后把这个m+n个观测值按照大小次序排序,然后记下每个观测值在混合排序下面的秩,之后分别把两个样本所得到的秩相加。记第一个样本观测值的秩的和为$W_{x}$,而第二个样本秩的和为$W_{Y}$。这两个值可以互相推算,称为Wilcoxon统计量。该统计量的分布和两个总体分布无关,,由此分布可以得到p值。直观上看,如果$W_{x}$与$W_{Y}$之中有一个显著地大(或显著地小),则可以选择拒绝零假设。这个检验注称为Wilcoxon秩和检验(Wilcoxon rank-sum test),也称为Mann-Whitney检验或Mann-Whitney-Wilcoxon检验。之所以有两个名称,这是因为Wilcoxon统计量和由Mann-Whitney导出的检验统计量等价。Mann-Whitney统计量也是一对:$W_{XY}$和$W_{YX}$;定义为两个样本中满足$x_{i}>y_{i}$的数目,而$W_{XY}$定义为两个样本中满足$x_{i}<y_{i}$的数目。检验时,一般使用$W=min(W_{XY},W_{YX})$作为检验统计量。

案例A:(《医学统计学》,第三版,孙振球,P136)

对10例肺癌病人和12例矽肺0期工人用X光片测量肺门横径右侧距RD值(cm),结果如下所示:

1
2
肺癌:2.78,3.23,4.2,4.87,5.12,6.21,7.18,8.05,8.56,9.6
矽肺:3.23,3.5,4.04,4.15,4.28,4.34,4.47,4.64,4.75,4.82,4.95,5.1

问肺癌病人的RD值是否高于矽肺0期工人的RD值?

思路:第一组数据的样本量为10,中位数是5.665,第二组数据的样本量为12,中位数是4.405,这两个中位数看上去有点差异,令这两组数据的总体中位数分别为$M_{1}$和$M_{2}$,现在进行检验,如下所示:

计算过程如下所示:

1
2
3
lc <- c(2.78,3.23,4.2,4.87,5.12,6.21,7.18,8.05,8.56,9.6)
si <- c(3.23,3.5,4.04,4.15,4.28,4.34,4.47,4.64,4.75,4.82,4.95,5.1)
wilcox.test(lc,si,correct=T)

从结果中我们可以看到,p值等于0.04318,同时也得到中间结果$W_{XY}=86.5$,因此哦可以说,对于大于p值的显著必不平都可以拒绝零假设,也就是说,这两组数据的中位数有显著性的差异。

配对Wilcoxon符号秩检验

例8-1:对12份血清分别用原方法(检测时间20分钟)和新方法(检测时间10分钟)测谷-丙转氨酶,结果见表8-1的(2)、(3)栏。问两法所得结果有无差别?(《医学统计学》,第三版,孙振球,P132)

1
2
3
old <- c(60,142,195,80,242,220,190,25,198,38,236,95)
new <- c(76,152,243,82,240,220,205,38,243,44,190,100)
wilcox.test(old,new,paired = TRUE)

结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> old <- c(60,142,195,80,242,220,190,25,198,38,236,95)
> new <- c(76,152,243,82,240,220,205,38,243,44,190,100)
> wilcox.test(old,new,paired = TRUE)
Wilcoxon signed rank test with continuity correction
data: old and new
V = 11.5, p-value = 0.06175
alternative hypothesis: true location shift is not equal to 0
Warning messages:
1: In wilcox.test.default(old, new, paired = TRUE) :
无法精確計算带连结的p值
2: In wilcox.test.default(old, new, paired = TRUE) :
有0时无法計算精確的p值

有序的秩检验

例8-4 39名吸烟工人和40名不吸烟工人的碳氧血红蛋白HbCO(%)含量见表8-6。问吸烟工人的HbCO(%)含量是否高于不吸烟工人的HbCO(%)含量?

例8-4第1种方法:Wilcox.test检验:

1
2
3
4
5
6
7
8
smoke <- c(1,8,16,10,4)
no.smoke <-c(2,23,11,4,0)
rank.c <- c(1:5)
group1 <- rep(rank.c,smoke)
group2 <- rep(rank.c,no.smoke)
data84 <- c(group1,group2)
group.f <-factor(c(rep(1,length(group1)),rep(2,length(group2))))
wilcox.test(data84~group.f)

结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
> wilcox.test(data84~group.f)
Wilcoxon rank sum test with continuity correction
data: data84 by group.f
W = 1137, p-value = 0.0002181
alternative hypothesis: true location shift is not equal to 0
Warning message:
In wilcox.test.default(x = c(1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, :
无法精確計算带连结的p值

例8-4第2种方法:Kruskal检验:

Kurskal-Wallis检验是Wilcoxon方法(其实是Mann-Whitney检验)用于多于两个样本的时候的升级版。当对两个样本进行比较的时候,Kurskal-Wallis检验与Mann-Whitney检验是等价的。

1
kruskal.test(data84~group.f)

结果如下所示:

1
2
3
4
5
6
> kruskal.test(data84~group.f)
Kruskal-Wallis rank sum test
data: data84 by group.f
Kruskal-Wallis chi-squared = 13.707, df = 1, p-value = 0.0002137

例8-4第2种方法:Ridit检验:

1
2
3
4
5
6
7
8
9
data84 <- matrix(c(1,8,16,10,4,2,23,11,4,0),nrow=5)
dimnames(data84) <- list(cone=c("very low","low","median","a bit high","high"),
worker=c("smoker","no-smoker"))
if(!require("Ridit")){
install.packages("Ridit")
library(Ridit)
}
ridit(data84,2)
chisq.test(data84)

结果如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
> ridit(data84,2)
Ridit Analysis:
Group Label Mean Ridit
----- ----- ----------
1 smoker 0.6159
2 no-smoker 0.387
Reference: Total of all groups
chi-squared = 13.707, df = 1, p-value = 0.0002137
> chisq.test(data84)
Pearson's Chi-squared test
data: data84
X-squared = 15.079, df = 4, p-value = 0.004541
Warning message:
In chisq.test(data84) : Chi-squared近似算法有可能不准

例8-5

用三种药物杀灭钉螺,每批用200只活钉螺,用药后清点每批钉螺的死亡数、再计算死亡率(%),结果见表8-9。问三种药物杀灭钉螺的效果有无差别?

1
2
3
4
drug <-rep(c("甲药","乙药","丙药"),each=5)
data <- c(32.5,35.5,40.5,46,49,16,20.5,22.5,29,36,6.5,9.0,12.5,18,24)
data85 <- data.frame(drug,data)
kruskal.test(data85$data~data85$drug)

例8-6

比较小白鼠接种三种不同菌型伤寒杆菌9D、11C和DSC1后存活日数,结果见表8-10。问小白鼠接种三种不同菌型伤寒杆菌的存活日数有无差别?

1
2
3
4
mice <- as.factor(c(rep("9D",10),rep("11C",9),rep("DSC1",11)))
data86 <- c(2,2,2,3,4,4,4,5,7,7,5,5,6,6,6,7,8,10,12,3,5,6,6,6,7,7,9,10,11,11)
data86 <- data.frame(mice,data)
kruskal.test(data86$data~data86$mice)

例8-7

四种疾病患者痰液内嗜酸性白细胞的检查结果见表8-11。问四种疾病患者痰液内的嗜酸性白细胞有无差别?注:这道例题与《医学统计学及SAS应用》(上海交通大学)的9.11类似

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
x1 <- c(0,2,9,6)
x2 <- c(3,5,5,2)
x3 <- c(5,7,3,2)
x4 <- c(3,5,3,0)
freq <- function(x){
count <-c()
for(i in 1:4){
count1 <-c(rep(i,x[i]))
count <- append(count,count1)
}
return(count)}
data87 <-c(freq(x1),freq(x2),freq(x3),freq(x4))
group <- c(rep(1,sum(x1)),rep(2,sum(x2)),rep(3,sum(x3)),rep(4,sum(x4)))
kruskal.test(data87~group)

例8-8

对例8-6资料(表8-10)作三个样本间的两两比较,Nemenyi检验。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 需要安装下列包:
if(!require("pgirmess")){
install.packages("pgirmess")
library(pgirmess)
}
if(!require("coin")){
install.packages("coin")
library(coin)
}
if(!require("multcomp")){
install.packages("multcomp")
library(multcomp)
}
mice <- as.factor(c(rep("9D",10),rep("11C",9),rep("DSC1",11)))
data <- c(2,2,2,3,4,4,4,5,7,7,5,5,6,6,6,7,8,10,12,3,5,6,6,6,7,7,9,10,11,11)
data88 <- data.frame(mice,data)
kruskal.test(data~mice,data=data88)
kruskalmc(data~mice, data=data88, probs=0.05) # 使用kruskalmc函数做两两比较,但此方法不能给出具体的值
# 下面构建函数计算具体的p值
mult <- oneway_test(data ~ mice, data = data88,
ytrafo = function(data) trafo(data, numeric_trafo = rank),
xtrafo = function(data) trafo(data, factor_trafo = function(x)
model.matrix(~x - 1) %*% t(contrMat(table(x), "Tukey"))),
teststat = "max", distribution = approximate(B = 90000))
pvalue(mult, method = "single-step") #计算具体的p值

例8-9

8名受试对象在相同实验条件下分别接受4种不同频率声音的刺激,他们的反应率(%)资料见表8-12。问4种频率声音刺激的反应率是否有差别?

1
2
3
4
5
6
freA <- c(8.40,11.60,9.40,9.80,8.30,8.60,8.90,7.80)
freB <- c(9.60,12.70,9.10,8.70,8.00,9.80,9.00,8.20)
freC <- c(9.80,11.80,10.40,9.90,8.60,9.60,10.60,8.50)
freD <- c(11.70,12.00,9.80,12.00,8.60,10.60,11.40,10.80)
matrix89 <- matrix(c(freA,freB,freC,freD),nrow=8,dimnames=list(no=1:8,c("A","B","C","D")))
friedman.test(matrix89)

对两个以上样本进行比较的Kruskal-Wallis 秩和检验
kruskal.test()
kruskal.test(formula, data, subset, na.action, …)
例子 为了比较属于同一类的四种不同食谱的营养效果,将25只老鼠随机的氛围4组,每组分别为8只,4只,7只和6只,采用食谱甲乙丙丁喂养,假设其他条件均值相同,12周后测得体重增加量如表所示,在alpha=0.05水平上,检验各食谱的营养效果是否有显著差异。

1
2
3
4
5
6
7
8
food<-data.frame(
x=c(164, 190, 203, 205, 206, 214, 228, 257,
185, 197, 201, 231,
187, 212, 215, 220, 248, 265, 281,
202, 204, 207, 227, 230, 276),
g=factor(rep(1:4, c(8,4,7,6)))
)
kruskal.test(x~g, data=food)

另一种写法

1
kruskal.test(food$x, food$g)


1
2
3
4
5
A<-c(164, 190, 203, 205, 206, 214, 228, 257)
B<-c(185, 197, 201, 231)
C<-c(187, 212, 215, 220, 248, 265, 281)
D<-c(202, 204, 207, 227, 230, 276)
kruskal.test(list(A,B,C,D))

  利用R做Nemenyi的检验方法有人介绍过,SPSS里面没有现成的方法,需要编程,这里用R来做一下这个检验,原文是在丁香园引用的,参见(R语言)秩和检验后两两比较方法之Nemenyi 检验及其他这篇帖子。  

原题:比较以下三组之间的数据,看有无差异
第一组:293,409,392,213,409,57,97,244,254,352,168;
第二组:441,538,390,589,244,409,72,168,254,374 ;
第三组:807,833,409,914,380,883,254,993,667 ;
将上面三组数据录入data20140501,分两列,第一列为cd,第2列为group,存为csv格式。

源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
datanemenyi <- read.csv("D:/Tutorial/20151219Statistics/data/rdata/data20140501.csv") #导入源数据文件
str(datanemenyi) #查看数据结构
datanemenyi$group <- as.factor(datanemenyi$group);datanemenyi #将group转化为因子类型
kruskal.test(cd~group, data=datanemenyi) # Kruskal-Wallis检验,类似于参数检验的ANOVA检验
library(pgirmess)
library(coin)
library(multcomp) # 安装并加载要用到的包
kruskalmc(cd~group, data=datanemenyi, probs=0.05) # 使用kruskalmc函数做两两比较,此法不能给出精确p值
mult <- oneway_test(cd ~ group, data = datanemenyi,
ytrafo = function(data) trafo(data, numeric_trafo = rank),
xtrafo = function(data) trafo(data, factor_trafo = function(x)
model.matrix(~x - 1) %*% t(contrMat(table(x), "Tukey"))),
teststat = "max", distribution = approximate(B = 90000))
pvalue(mult, method = "single-step")

这个结果与原代码的运行结果不同

参考资料

  1. 关于Nemenyi检验的方法是参照丁香园的,原贴地址如下,帖子的作者有把写过《医学统计学及SAS应用》之R语言实现这本电子书,下载地址如下:Nemenyi检验方法
  2. 《医学统计学及SAS应用》之R语言实现