Chapter 5 Bootstrap,Jackknife和Permutation
5.1 Bootstrap
5.1.1 Bootstrap估计
Bootstrap是一类非参数蒙特卡洛方法,它主要通过重采样来估计总体的分布,对总体分布没有做假设,这也是非参数的重要特点。一般地,Bootstrapping方法的模式图如下:F→XX↔Fn→ˆθ(real data),Fn→XX⋆↔F⋆n→ˆθ⋆n(resampling data).
因此,算法的流程如下:
- 给定原始样本 x1,…,xn 和参数 θ 的估计量 ˆθ.
- 对第 b(b=1,…,B) 次Bootstrap:
- 通过对观测样本 {x1,…,xn} 有放回抽样得到样本 xx⋆(b)={x⋆b1,…,x⋆bn};
- 利用这个样本计算 θ 的估计值 ˆθ⋆(b).
- Fˆθ(⋅) 的Bootstrap估计就是 ˆθ⋆(1),…,ˆθ⋆(B) 的经验分布函数。
这一过程是具有理论保障的。事实上,在一定的正则条件下,当 n→∞ 时,supx|P(√n(ˆθ⋆−ˆθ−E(ˆθ−θ0))≤x∣XX)−P(√n(ˆθ−θ0−E(ˆθ−θ0))≤x)|P→0.
5.1.2 Bootstrap估计偏差与标准误差
估计的偏差E(ˆθ)−θ0≈E(ˆθ⋆−ˆθ∣XX)=E(ˆθ⋆∣XX)−ˆθ可以用 ¯θ⋆−ˆθ 来估计,其中¯θ⋆=1BB∑b=1ˆθ⋆(b) 是 ˆθ⋆ 的样本均值。而 ˆθ 的标准误差可以用 ˆθ⋆ 的样本标准误差来估计:√1B−1B∑b=1(ˆθ⋆(b)−¯θ⋆)2.
考虑有限样本x={2,2,1,1,5,4,4,3,1,2}. 感兴趣参数为均值,利用如下代码可以实现Bootstrap估计。
<- c(2, 2, 1, 1, 5, 4, 4, 3, 1, 2)
x <- mean(x)
theta <- 10000
B <- numeric(B)
thetastar for (b in 1:B) {
<- sample(x, replace = TRUE)
xstar <- mean(xstar)
thetastar[b]
}round(c(bias = mean(thetastar) - theta,
se.boot = sd(thetastar),
se.sample = sd(x) / sqrt(length(x))), 4)
bias se.boot se.sample
-0.0027 0.4266 0.4534
可以看到估计的偏差很低,而且Bootstrap标准误差与实际标准误差十分接近。
hist(thetastar)
abline(v = theta, col = 'red', lwd = 2)
此外,利用boot
包里的boot
函数也可以实现Bootstrap。注意boot
函数中的参数statistic
是一个函数,用于返回感兴趣的统计量的值,它必须至少有两个参数,其中第一个是数据,第二个表示Bootstrap抽样中的指标向量、频率或权重等。
library(boot)
library(MASS)
<- function(x, i) { cor(x[i,1], x[i,2]) }
b.cor
# zero mean the corvariance matrix
set.seed(12345)
<- 100
n <- mvrnorm(n, rep(0, 2), matrix(c(1, 0.8, 0.8, 1), 2))
x
<- boot(data = x, statistic = b.cor, R = 1000)
obj round(c(original = obj$t0,
bias = mean(obj$t) - obj$t0,
se.boot = sd(obj$t)), 4)
## original bias se.boot
## 0.8338 -0.0022 0.0304
对协方差的原始估计不准是因为产生的样本只有100个,但是Bootstrap的效率很高,估计的偏差很低。
又如,假设 x=(x1,…,x10)∼N(μ,σ2),利用如下代码可以求 σ2 的估计量 ˆσ2=1nn∑i=1(xi−¯x)2 的Bootstrap偏差。
<- 10
n <- rnorm(n, mean = 0, sd = 10)
x <- (n - 1) * var(x) / n
sigma2.hat
# Bootstrap
<- 1000
B <- numeric(B)
sigma2.b for (b in 1:B) {
<- sample(1:n, size = n, replace = TRUE)
i <- (n - 1) * var(x[i]) / n
sigma2.b[b]
}<- mean(sigma2.b) - sigma2.hat
bias bias
## [1] -4.730601
可以看到 ˆσ2 低估了参数 σ2。
5.1.3 Bootstrap置信区间
一般而言,标准Bootstrap置信区间是最简单的方法,但有时候它往往并不是最优的。根据中心极限定理可知置信水平为 1−α 的近似置信区间为(ˆθ−zα/2^se(ˆθ),ˆθ+zα/2^se(ˆθ)), 其中 zα/2 是标准正态分布的上 α/2 分位数。
学生化Bootstrap置信区间是对上述方法的修正,它对应置信水平为 1−α 的近似置信区间为(ˆθ−tα/2^se(ˆθ),ˆθ+tα/2^se(ˆθ)),
其中 tα/2 是 (ˆθ(b)−ˆθ)/^se(ˆθ(b)) 的上 α/2 分位数,注意 ^se(ˆθ(b)) 涉及到二次重采样。
基本Bootstrap置信区间通过对重采样样本减去观察到的统计量来得到转换后的分布,利用此得到置信区间。具体来说,注意到 ˆθ⋆−ˆθ∣XX 和 ˆθ−θ 具有相同的极限分布,因此置信水平为 1−α 的置信区间为(ˆθ−F−1(1−α/2),ˆθ−F−1(α/2)), 其中 F−1(x) 可以用 ˆθ⋆−ˆθ 的 x 分位数 ˆθ⋆x−ˆθ 来估计,因此最终置信水平为 1−α 的近似置信区间为(2ˆθ−ˆθ⋆1−α/2,2ˆθ−ˆθ⋆α/2).
分位数Bootstrap置信区间直接利用重采样样本的经验分布作为建议分布,将其分位数作为 ˆθ 的分位数估计,得到置信水平为 1−α 的近似置信区间 (ˆθ⋆α/2,ˆθ⋆1−α/2).
偏差修正和加速(BCa)置信区间 (ˆθ⋆α1,ˆθ⋆α2) 对上述分位数进行了修正:α1=Φ(ˆz0+ˆz0−zα/21−ˆa(ˆz0−zα/2)),α2=Φ(ˆz0+ˆz0+zα/21−ˆa(ˆz0+zα/2)), 其中 ˆz0=Φ−1(1BB∑b=1I(ˆθ⋆(b)<ˆθ)) 是偏差修正项,ˆa=n∑i=1(¯θ⋆(⋅)−θ(i))36(n∑i=1(¯θ⋆(⋅)−θ(i))2)3/2 是偏度(加速项)。
BCa置信区间具有良好的性质:
- 不变性,即若 θ 的置信区间为 (ˆθ⋆α1,ˆθ⋆α2),g(⋅) 为一一变换函数,则 g(θ) 的置信区间为 (g(ˆθ⋆α1),g(ˆθ⋆α2));
- 二阶精确性,即误差以 1/n 的速度趋于0.
上述置信区间都可以用boot::boot.ci
得到对应的结果。
library(boot)
set.seed(12345)
<- 1; b <- 1; n <- 10; m <- 100
mu <- function(x, i) { median(x[i]) }
boot.median <- ci.basic <- ci.perc <- ci.bca <- matrix(NA, m, 2)
ci.norm for (i in 1:m) {
<- runif(n, -0.5, 0.5)
U <- mu - b * sign(U) * log(1 - 2 * abs(U))
R <- boot(data = R, statistic = boot.median, R = 500)
de <- boot.ci(de, type = c("norm", "basic", "perc", "bca"))
ci <- ci$norm[2:3]
ci.norm[i,] <- ci$basic[4:5]
ci.basic[i,] <- ci$perc[4:5]
ci.perc[i,] <- ci$bca[4:5]
ci.bca[i,]
}cat("norm =", mean(ci.norm[, 1] <= mu & ci.norm[, 2] >= mu),
"basic =", mean(ci.basic[, 1] <= mu & ci.basic[, 2] >= mu),
"perc =", mean(ci.perc[, 1] <= mu & ci.perc[, 2] >= mu),
"bca =", mean(ci.bca[, 1] <= mu & ci.bca[, 2] >= mu))
norm = 0.95 basic = 0.9 perc = 0.93 bca = 0.92
可以看到只有正态置信区间的覆盖概率都高于95%,其余都低于95%。
5.2 Jackknife
5.2.1 Jackknife估计
Jackknife类似于交叉验证方法中的“留一(leave-one-out)交叉验证”。令 x=(x1,…,xn) 为观测到的样本,定义第 i 个Jackknife样本为丢掉第 i 个样本后的剩余样本,即x(i)=(x1,…,xi−1,xi+1,…,xn). 若 ˆθ=Tn(x),则第 i 个Jackknife重复为 ˆθ(i)=Tn−1(x(i)),i=1,…,n。
5.2.2 Jackknife估计偏差与标准误差
对偏差 E(ˆθ)−θ0 的无偏估计为(n−1)(¯ˆθ(⋅)−ˆθ), 其中 ¯ˆθ(⋅)=1nn∑i=1ˆθ(i)。
下面以 θ 为总体方差为例来说明为什么偏差的Jackknife估计中系数是 n−1。注意到方差的plug-in估计ˆθ=1nn∑i=1(xi−¯x)2 是 σ2 的无偏估计,其偏差为bias(ˆθ)=E(ˆθ)−σ2=−σ2n. 由于每个Jackknife估计是基于样本量为 n−1 的样本构造的,因此Jackknife重复 ˆθ(i) 的估计偏差为 −σ2n−1=nn−1bias(ˆθ),从而E[ˆθ(i)−ˆθ]=bias(ˆθ(i))−bias(ˆθ)=bias(ˆθ)n−1. 所以在Jackknife偏差估计中的系数为 n−1。
对标准差 se(ˆθ) 的无偏估计为^se(ˆθ)=√n−1nn∑i=1(ˆθ(i)−¯ˆθ(⋅))2.
下面以 θ 为总体均值为例来说明为什么标准差的Jackknife估计中系数是 n−1n。注意到样本均值 ˆθ=¯x 的方差估计为^Var(ˆθ)=ˆσ2n=1n(n−1)n∑i=1(xi−¯x)2. 注意到 ˆθ(i)=n¯x−xin−1,于是 ¯ˆθ(⋅)=1nn∑i=1ˆθ(i)=ˆθ,ˆθ(i)−¯ˆθ(⋅)=¯x−xin−1, 所以在Jackknife标准差估计中的系数为 n−1n。
例如,在之前那个估计多元正态随机变量相关系数的例子中,考虑使用Jackknife估计如下。
library(MASS)
set.seed(12345)
<- 100
n <- mvrnorm(n, rep(0, 2), matrix(c(1, 0.8, 0.8, 1), 2))
x <- b.cor(x, 1:n)
theta.hat <- numeric(n)
theta.jack for (i in 1:n) {
<- b.cor(x,(1:n)[-i])
theta.jack[i]
}
<- mean(theta.jack)
theta.jack.mean <- (n - 1) * (theta.jack.mean - theta.hat)
bias.jack <- sqrt((n - 1) * mean((theta.jack - theta.jack.mean)^2))
se.jack round(c(original = theta.hat, bias.jack = bias.jack, se.jack = se.jack, se.boot = sd(obj$t)), 4)
## original bias.jack se.jack se.boot
## 0.8338 -0.0012 0.0297 0.0304
可以看到Jackknife估计比Bootstrap估计要稍好一些。
5.2.3 Jackknife失效情形
如果估计量 ˆθ 不够平滑,Jackknife方法可能就会失效。中位数就是一个不平滑统计量的例子。
<- 100; m <- 100
n <- numeric(n)
M <- var.boot <- est <- numeric(m)
var.jack <- function(x, i) { median(x[i]) }
b.median for (k in 1:m) {
<- rnorm(n)
x <- median(x)
est[k] for (i in 1:n) { M[i] <- median(x[-i]) }
<- mean(M)
M.mean <- (n - 1) * mean((M - M.mean)^2)
var.jack[k] <- var(boot(x, b.median, R = 500)$t)
var.boot[k]
}round(c(v.emp = var(est), v.boot = mean(var.boot), v.jack = mean(var.jack)), 4)
## v.emp v.boot v.jack
## 0.0154 0.0162 0.0243
可以看到Jackknife估计和Bootstrap估计和经验估计相差甚远,这显然是失效了。
5.3 Jackknife-after Bootstrap
前面介绍了使用一个估计量的偏差和标准差的Bootstrap估计,这些估计本身又是统计量,这些估计量的方差就可以用Jackknife方法来估计。
注意到 ^se(ˆθ) 是 B 次 ˆθ 的Bootstrap重复统计量的样本标准差,如果我们丢掉第 i 个样本,则Jackknife算法就是对每个 i,从剩下的 n−1 个样本值中再抽样 B 次,来计算 ^se(ˆθ(i)),即一个Jackknife重复。最终得到^se(^seB(ˆθ))=√n−1nn∑i=1(^seB(i)(ˆθ)−¯^seB(⋅)(ˆθ))2, 其中 ¯^seB(⋅)(ˆθ)=1nn∑i=1^seB(i)(ˆθ)。
不过,这样做效率比较低,我们有方法可以避免重复Bootstrap。
记 x∗i=(x∗1,…,x∗n) 为一次Bootstrap抽样,x∗1,…,x∗B 表示样本大小为 B 的Bootstrap样本。令 J(i) 为Bootstrap样本中不含 xi 的那些样本指标,B(i) 为不含 xi 的Bootstrap样本个数,因此我们可以使用丢掉 B−B(i) 个含有 xi 的样本后其余的样本来计算一个Jackknife重复,故标准差估计量的Jackknife估计为^sejack(^seB(ˆθ))=√n−1nn∑i=1(^seB(i)−¯^seB(⋅))2, 其中 ^seB(i)=√1B(i)∑j∈J(i)[ˆθ(j)−¯ˆθ(J(i))]2, ¯ˆθ(J(i))=1B(i)∑j∈J(i)ˆθ(j)。
还是以之前那个估计多元正态随机变量相关系数的例子为例。
library(MASS)
set.seed(12345)
<- 100
n <- mvrnorm(n, rep(0, 2), matrix(c(1, 0.8, 0.8, 1), 2))
x <- 1000
B <- numeric(B)
theta.boot # set up storage for the sampled indices
<- matrix(0, nrow = B, ncol = n)
indices
# jackknife-after-bootstrap step 1: run the bootstrap
for (b in 1:B) {
<- sample(1:n, size = n, replace = TRUE)
i <- b.cor(x, i)
theta.boot[b] # save the indices for the jackknife
<- i
indices[b, ]
}
# jackknife-after-bootstrap to est. se(se)
<- numeric(n)
se.jack for (i in 1:n) {
# in i-th replicate omit all samples with x[i]
<- (1:B)[apply(indices, 1, function(k) { !any(k == i) })]
keep <- sd(theta.boot[keep])
se.jack[i]
}
<- mean(se.jack)
se.jack.mean <- sqrt((n - 1) * mean((se.jack - se.jack.mean)^2))
se.se.boot round(c(se.boot = sd(theta.boot), se.se.boot = se.se.boot), 4)
## se.boot se.se.boot
## 0.0314 0.0102
5.4 Jackknife的应用:交叉验证
交叉验证(Cross Validation)是一种分割数据方法,可以用来验证参数估计的稳健性、分类算法的准确度、模型的合理性(惩罚项调节参数 λ 的选取)等等。Jackknife可以被视作是交叉验证的一种特例,其主要用于估计偏差和估计量的标准差。
最简单的交叉验证方法是所谓的hold out方法,其基本思想是:将数据随机分成训练集和验证集,然后仅使用训练集对样本进行建模,再通过验证集来对模型进行评估。但这种方法依赖于数据的分隔方式,结果容易出现波动性。
k-折交叉验证是对hold out方法的改进,其基本思想是:将数据分成 k 个子集,然后重复hold out方法 k 次,每次第 i 个子集被作为验证集,而其他 k−1 个子集被作为训练集进行建模,最后计算 k 次的平均误差。
前面所介绍的Jackknife(Leave-one-out)实际上就是 n-折交叉验证,计算的时间复杂度较高。
下面的例子是交叉验证在模型选择中的应用。包DAAG
里的ironslag
数据描述了两种方法(chemical和magnetic)测量含铁量的53次结果。散点图显示chemical和magnetic变量是正相关的,但是这种关系可能不是线性的——多项式模型、指数模型、对数模型可能更好地拟合数据。
基于此,我们候选的模型有
- 线性模型: Y=β0+β1X+ε;
- 多项式模型: Y=β0+β1X+β2X2+ε;
- 指数模型: lnY=β0+β1X+ε;
- 对数模型: lnY=β0+β1lnX+ε。
par(mfrow = c(2, 2))
attach(DAAG::ironslag)
<- seq(10, 40, 0.1)
a
<- lm(magnetic ~ chemical)
L1 plot(chemical, magnetic, main = "Linear", pch = 16)
<- L1$coef[1] + L1$coef[2] * a
yhat1 lines(a, yhat1, lwd = 2)
<- lm(magnetic ~ chemical + I(chemical^2))
L2 plot(chemical, magnetic, main = "Quadratic", pch = 16)
<- L2$coef[1] + L2$coef[2] * a + L2$coef[3] * a^2
yhat2 lines(a, yhat2, lwd = 2)
<- lm(log(magnetic) ~ chemical)
L3 plot(chemical, magnetic, main = "Exponential", pch = 16)
<- exp(L3$coef[1] + L3$coef[2] * a)
yhat3 lines(a, yhat3, lwd = 2)
<- lm(log(magnetic) ~ log(chemical))
L4 plot(log(chemical), log(magnetic), main = "Log-Log", pch = 16)
<- L4$coef[1] + L4$coef[2] * log(a)
logyhat4 lines(log(a), logyhat4, lwd = 2)
然后使用交叉验证方法对每个模型的预测误差进行估计。
- 对 k=1,…,n,令 (xk,yk) 为验证样本,使用其余样本对模型参数进行估计,然后计算预测误差。
- 使用其余的样本 (xi,yi) (i=1,…,k−1,k+1,…,n) 对模型进行拟合;
- 计算预测值: ˆyk=ˆβ0+ˆβ1xk;
- 计算预测误差: ek=yk−ˆyk。
- 计算均方误差 σ2e=1nn∑i=1e2k。
<- length(magnetic)
n <- e2 <- e3 <- e4 <- numeric(n)
e1 for (k in 1:n) {
<- magnetic[-k]
y <- chemical[-k]
x
<- lm(y ~ x)
J1 <- J1$coef[1] + J1$coef[2] * chemical[k]
yhat1 <- magnetic[k] - yhat1
e1[k]
<- lm(y ~ x + I(x^2))
J2 <- J2$coef[1] + J2$coef[2] * chemical[k] + J2$coef[3] * chemical[k]^2
yhat2 <- magnetic[k] - yhat2
e2[k]
<- lm(log(y) ~ x)
J3 <- exp(J3$coef[1] + J3$coef[2] * chemical[k])
yhat3 <- magnetic[k] - yhat3
e3[k]
<- lm(log(y) ~ log(x))
J4 <- exp(J4$coef[1] + J4$coef[2] * log(chemical[k]))
yhat4 <- magnetic[k] - yhat4
e4[k]
}c(Linear = mean(e1^2), Quad = mean(e2^2), Exp = mean(e3^2), LogLog = mean(e4^2))
## Linear Quad Exp LogLog
## 19.55644 17.85248 18.44188 20.45424
结果表明使用二次多项式回归的预测误差更小,因此考虑选择模型L2
。
par(mfrow = c(2, 2))
plot(L2)
5.5 Permutation
置换(Permutation)检验同样基于重采样,它是不放回抽样,往往用于非参数假设检验问题。
同分布检验:H0:F=G↔Ha:F≠G.
多
独立检验:H0:FX,Y=FXFY↔Ha:FX,Y≠FXFY.
关联分析:对GLM问题g{E(Y∣X,Z)}=α+βTX+γTZ,
在给定 Z 条件下的独立性检验:H0:β=0↔Ha:β≠0.
5.5.1 置换分布
设样本 XX=(X1,…,Xn) 和 YY=(Y1,…,Ym) 分别来自分布 FX 和 FY。令ZZ=(Z1,…,ZN)=(X1,…,Xn,Y1,…,Ym) 为合样本(其中 N=n+m),而 ZZ∗=(XX∗,YY∗) 为 ZZ 的一个置换(注意这里 XX∗ 并不一定是 XX 的一个置换)。
设检验统计量为 T=T(XX,YY),则置换检验统计量为 T∗=T(XX∗,YY∗)。如果 T 与样本 XX 和 YY 的顺序无关,那么它有 \binom{N}{n} 个可能取值 T_1^*,\dots,T_{\binom{N}{n}}^*。一个直观的想法是,在原假设 H_0:F_X=F_Y 下,每个置换的概率应当等可能的是 1/\binom{N}{n},从而 T^* 的分布函数为F_{T^*}(t)=\binom{N}{n}^{-1}\sum_{j=1}^{\binom{N}{n}}I(T_j^*\leq t). 这个c.d.f.可以近似为 T 的零分布。于是检验的p值为\mathbb P_{H_0}(|T^*|\geq|T|\mid\text{data})=\binom{N}{n}^{-1}\sum_{j=1}^{\binom{N}{n}}I(|T_j^*|\geq|T|).
当 N 比较小时,所有置换的可能种数也很少,可以直接按上述方法计算,但是当 N 很大时,我们需要做近似,即从中不放回抽样地选取一部分样本进而计算。
- 计算原检验统计量的值 T=T(\pmb X,\pmb Y);
- 对第 b(b=1,\dots,B) 次重复:
- 生成一次置换样本 \pmb Z_b^*=(\pmb X_b^*,\pmb Y_b^*);
- 计算检验统计量的值 T_b^*=T(\pmb X_b^*,\pmb Y_b^*).
- 如果检验统计量的值越大就越倾向于备择假设,则p值约为 \hat{p}=\dfrac{1+\sharp\{T_b^*\geq T\}}{1+B}=\dfrac{1+\sum\limits_{b=1}^BI(T_b^*\geq T)}{1+B}. 对其他两种备择假设的形式计算类似.
- 当 \hat{p}\leq\alpha 时就在检验水平为 \alpha 上拒绝原假设 H_0.
例如,对两样本 t 检验,可以采用如下代码实现置换检验。
attach(chickwts)
<- sort(as.vector(weight[feed == "soybean"]))
x <- sort(as.vector(weight[feed == "linseed"]))
y detach(chickwts)
cat(' x:', x, '\n', 'y:', y)
## x: 158 171 193 199 230 243 248 248 250 267 271 316 327 329
## y: 141 148 169 181 203 213 229 244 257 260 271 309
<- 999
R <- c(x, y)
z <- 1:length(z)
K <- length(x)
n <- numeric(R)
reps <- t.test(x, y)$statistic
t0 for (i in 1:R) {
<- sample(K, size = n, replace = FALSE)
k <- z[k]
x1 <- z[-k]
y1 <- t.test(x1, y1)$statistic
reps[i]
}<- mean(abs(c(t0, reps)) >= abs(t0))
p round(c(p, t.test(x, y)$p.value), 3)
## [1] 0.199 0.198
如果关心的问题是多重检验问题,则需要考虑进行p值修正,为了计算效率的提升,考虑如下方法:
- 对一个较大的 B 做一次多重检验问题;
- 剔除那些p值较大的假设,对剩下的假设再设定偏大的 B 做多重检验问题;
- 重复上述步骤直到p值的精度达到问题要求;
- 采用p值修正方法(如Bonferroni或FDR等)对p值进行调整。
5.5.2 同分布检验
设样本 \pmb X=(X_1,\dots,X_n) 和 \pmb Y=(Y_1,\dots,Y_m) 分别来自分布 F 和 G,要检验的问题是H_0:F=G\leftrightarrow H_a:F\neq G. 记合样本为 \pmb Z=(Z_1,\dots,Z_N)=(X_1,\dots,X_n,Y_1,\dots,Y_m),F 和 G 的经验分布函数分别为 F_n 和 G_m。
考虑单变量的两样本检验,利用K-S统计量D=\sup_{1\leq i\leq N}|F_n(z_i)-G_m(z_i)|作为检验统计量,它的值越大就越支持备择假设 H_a:F\neq G,表明两个分布之间的差距越大。
同样对于之前这个例题,我们使用基于K-S统计量的置换检验如下。
options(warn = -1)
<- numeric(R)
D <- ks.test(x, y, exact = FALSE)$statistic
D0 for (i in 1:R) {
<- sample(K, size = n, replace = FALSE)
k <- z[k]
x1 <- z[-k]
y1 <- ks.test(x1, y1, exact = FALSE)$statistic
D[i]
}mean(c(D0, D) >= D0)
## [1] 0.434
从结果中可以看到,我们没有充分的理由认为两样本来自的总体分布有差异。
除了利用K-S统计量,也可以使用Cramer-von Mises统计量W_2=\dfrac{mn}{(m+n)^2}\left[\sum_{i=1}^n(F_n(x_i)-G_m(x_i))^2+\sum_{j=1}^m(F_n(y_j)-G_m(y_j))^2\right] 作为检验统计量,它刻画了两个分布之间的融合平方距离,值越大就越支持备择假设 H_a:F\neq G,表明两个分布之间的差距越大。
同样对于之前这个例题,我们使用基于 W_2 的置换检验如下(标准包nortest::cvm.test
用于检验正态性,因此我们要重写函数)。
<- function(x, y, R = 999) {
cvm.test <- length(x)
n <- length(y)
m <- c(x, y)
z <- length(z)
N
# 以下标代替数值求样本点处的e.c.d.f.值
<- Gm <- numeric(N)
Fn for (i in 1:N) {
<- mean(z[i] <= x)
Fn[i] <- mean(z[i] <= y)
Gm[i]
}
<- (m * n) / N * sum((Fn - Gm)^2)
cvm0 <- numeric(R)
cvm for (i in 1:R) {
<- sample(1:N, size = n, replace = FALSE)
k <- z[k]
x1 <- z[-k]
y1 <- c(x1, y1)
z1 for (j in 1:N) {
<- mean(z1[j] <= x1)
Fn[j] <- mean(z1[j] <= y1)
Gm[j]
}<- (m * n) / N * sum((Fn - Gm)^2)
cvm[i]
}<- mean(c(cvm0, cvm) >= cvm0)
p return(c(statistic = cvm0, p.value = p))
}
cvm.test(x, y)
## statistic p.value
## 4.228022 0.404000
下面考虑多元变量的两样本检验问题,此时样本 X_1,\dots,X_n,Y_1,\dots,Y_m\in\mathbb R^d,则合样本为\pmb Z_{N\times d}=\left[\begin{array}{cccc} x_{11} & x_{12} & \cdots & x_{1d}\\ \vdots & \vdots & \ddots & \vdots\\ x_{n1} & x_{n2} & \cdots & x_{nd}\\ y_{11} & y_{12} & \cdots & y_{1d}\\ \vdots & \vdots & \ddots & \vdots\\ y_{m1} & y_{m2} & \cdots & y_{md} \end{array}\right].关心的假设检验问题仍然是 H_0:F=G\leftrightarrow H_a:F\neq G。
考虑最近邻(NN)检验,它基于合样本中的 r 阶最近邻。记 \text{NN}_r(Z_i) 为距离 Z_i 最近的第 r 个最近邻样本,l_i(r)=1 表示 Z_i 和 \text{NN}_r(Z_i) 来自同一个样本,否则其值为0。由此,考虑检验统计量T_{N,J}=\dfrac{1}{NJ}\sum_{i=1}^N\sum_{r=1}^Jl_i(r), 它的值越大就越支持备择假设 H_a:F\neq G,表明两个分布之间的差距越大。
代码中需要用到RANN
包中的nn2
函数,它用于找到样本的最近邻居,首先给出它的用法示例。
library(RANN) # for locating nearest neighbors
= data.frame(rnorm(10))
test_data nn2(data = test_data, k = 3)
## $nn.idx
## [,1] [,2] [,3]
## [1,] 1 10 7
## [2,] 2 7 10
## [3,] 3 8 6
## [4,] 4 9 5
## [5,] 5 2 7
## [6,] 6 8 1
## [7,] 7 2 10
## [8,] 8 6 3
## [9,] 9 4 5
## [10,] 10 1 7
##
## $nn.dists
## [,1] [,2] [,3]
## [1,] 0 0.01662495 0.07947581
## [2,] 0 0.00758830 0.07043916
## [3,] 0 0.20531098 0.33589143
## [4,] 0 0.08858641 0.72165808
## [5,] 0 0.60321477 0.61080307
## [6,] 0 0.13058045 0.30020783
## [7,] 0 0.00758830 0.06285086
## [8,] 0 0.13058045 0.20531098
## [9,] 0 0.08858641 0.63307167
## [10,] 0 0.01662495 0.06285086
结果中$nn.idx
给出了最近邻的下标,当然第一列就是它本身,在我们的算法中要将第一列去除,$nn.dists
给出了最近的距离,对我们算法而言没有帮助。
library(boot)
<- function(z, ix, sizes, J) {
Tn <- sizes[1]
n <- sizes[2]
m <- n + m
N if (is.vector(z)) { z <- data.frame(z) }
<- z[ix, ]
z <- nn2(data = z, k = J + 1)
NN <- NN$nn.idx[1:n, -1]
block1 <- NN$nn.idx[(n+1):N, -1]
block2 <- sum(block1 <= n)
i1 <- sum(block2 > n)
i2 return ((i1 + i2) / (N * J))
}
attach(chickwts)
<- as.vector(weight[feed == "sunflower"])
x <- as.vector(weight[feed == "linseed"])
y detach(chickwts)
<- c(x, y)
z
set.seed(12345)
<- boot(data = z, statistic = Tn, R = 9999,
boot.obj sim = "permutation", sizes = c(length(x), length(y)), J = 3)
<- c(boot.obj$t0, boot.obj$t)
ts <- mean(ts >= ts[1])
p c(statistic = ts[1], p.value = p)
## statistic p.value
## 0.8055556 0.0003000
可以看到检验的p值只有 3\times10^{-4},故拒绝原假设,认为 F\neq G。
hist(ts, freq = FALSE, main = "", xlab = "replicates of NN statistic (J = 3)")
abline(v = ts[1], col = "red", lwd = 2)
考虑能量(Energy)检验,提出检验统计量为能量距离e(\pmb X,\pmb Y)=\dfrac{nm}{n+m}\left(\dfrac{2}{nm}\sum_{i=1}^n\sum_{j=1}^m\|X_i-Y_j\|-\dfrac{1}{n^2}\sum_{i=1}^n\sum_{j=1}^n\|X_i-X_j\|-\dfrac{1}{m^2}\sum_{i=1}^m\sum_{j=1}^m\|Y_i-Y_j\|\right). 原假设下它的期望为零,因此过大的 e(\pmb X,\pmb Y) 将更倾向于备择假设 H_a:F\neq G,认为两个分布之间的差距越大。
library(energy)
<- eqdist.etest(z, sizes = c(length(x), length(y)), R = 9999)
boot.obs $p.value boot.obs
## [1] 1e-04
检验的p值为 1\times10^{-4},故拒绝原假设,认为 F\neq G。
考虑球统计量检验(Wang et al., 2018)。
library(Ball)
bd.test(x, y, num.permutation = 9999)$p.value
## bd.constant.pvalue
## 2e-04
检验的p值为 2\times10^{-4},故拒绝原假设,认为 F\neq G。
下面对这三种检验进行功效的比较。
<- m <- 50; N <- n + m; Nc <- c(n, m); R <- 999
n <- 100; J <- 3; p <- 2; mu <- 0.3
reps <- function(z, sizes, J) {
eqdist.nn <- boot(data = z, statistic = Tn, R = R,
boot.obj sim = "permutation", sizes = sizes, J = J)
<- c(boot.obj$t0, boot.obj$t)
ts <- mean(ts >= ts[1])
p return(list(statistic = ts[1], p.value = p))
}<- matrix(nrow = reps, ncol = 3)
p.value for (i in 1:reps) {
<- matrix(rnorm(n * p, 0, 1.5), ncol = p)
x <- cbind(rnorm(m), rnorm(m, mean = mu))
y <- rbind(x, y)
z 1] <- eqdist.nn(z, Nc, J)$p.value
p.value[i, 2] <- eqdist.etest(z, sizes = Nc, R = R)$p.value
p.value[i, 3] <- bd.test(x, y, R)$p.value
p.value[i,
}<- 0.1
alpha colMeans(p.value < alpha)
## [1] 0.53 0.79 0.95
可以看到,球统计量检验在非位置参数族的同分布检验问题中,有良好的功效。
5.6 Permutation的应用:距离相关系数
对随机向量 X\in\mathbb R^p 和 Y\in\mathbb R^q,关心对假设检验问题为H_0:F_{XY}=F_XF_Y\leftrightarrow H_a:F_{XY}\neq F_XF_Y. 考虑一个距离相关系数度量 R(X,Y),它应当满足:
- 0\leq R(X,Y)\leq1,\forall X,Y;
- R(X,Y)=0,当 X 和 Y 相互独立;
当 R(X,Y) 的值越大时,我们越倾向于备择假设 F_{XY}\neq F_XF_Y,即 X 和 Y 不独立。
定义变量内部成对距离 a_{kl}=\|X_k-X_l\|,b_{kl}=\|Y_k-Y_l\|,和经验距离协方差V_n^2(\pmb X,\pmb Y)=\dfrac{1}{n^2}\sum_{k=1}^n\sum_{l=1}^nA_{kl}B_{kl}, 其中 A_{kl}=a_{kl}-\overline{a}_{k\cdot}-\overline{a}_{\cdot l}+\overline{a}_{\cdot\cdot},B_{kl}=b_{kl}-\overline{b}_{k\cdot}-\overline{b}_{\cdot l}+\overline{b}_{\cdot\cdot} 是中心化的距离。
进一步定义经验距离相关系数为R_n^2(\pmb X,\pmb Y)=\left\{\begin{array}{ll} \dfrac{V_n^2(\pmb X,\pmb Y)}{\sqrt{V_n^2(\pmb X)V_n^2(\pmb Y)}}, & \text{若}~V_n^2(\pmb X)V_n^2(\pmb Y)>0,\\ 0, & \text{若}~V_n^2(\pmb X)V_n^2(\pmb Y)=0. \end{array}\right.
R_n^2(\pmb X,\pmb Y) 的极限零分布是具有二次形式的中心化正态随机变量,但系数与 \pmb X 和 \pmb Y 有关,但是我们可以构建置换检验。
<- function(x, y) {
dCov <- as.matrix(x); y <- as.matrix(y)
x <- nrow(x); m <- nrow(y)
n <- function(x) {
kl <- as.matrix(dist(x))
d <- rowMeans(d); m2 <- colMeans(d); M <- mean(d)
m1 <- sweep(d, 1, m1)
a <- sweep(a, 2, m2)
b return (b + M)
}<- kl(x); B <- kl(y)
A return (sqrt(mean(A * B)))
}
<- as.matrix(iris[1:50, 1:4])
z <- z[, 1:2]
x <- z[, 3:4]
y dCov(x, y)
## [1] 0.06436159
# a wrap-up of dCov for permutation test
<- function(z, ix, dims) {
ndCov2 <- dims[1]; q <- dims[2]; d <- p + q
p <- z[, 1:p]; y <- z[ix, -(1:p)]
x return(nrow(z) * dCov(x, y)^2)
}
<- boot(data = z, statistic = ndCov2, R = 999,
boot.obj sim = "permutation", dims = c(2, 2))
<- c(boot.obj$t0, boot.obj$t)
tb <- mean(tb >= tb[1])
p.cor p.cor
## [1] 0.077
因此在水平 \alpha=0.10 下原假设被拒绝,认为 X 与 Y 不独立。
hist(tb, nclass = "scott", xlab = "", main = "", freq = FALSE)
abline(v = tb[1], col = "red", lwd = 2)
考虑Ball
包中的多元随机向量独立性检验结果如下。
<- bcov.test(x, y, 999)$p.value
p.ball p.ball
## bcov.constant.pvalue
## 0.211