为什么对重采样数据集的假设检验经常拒绝空值?

机器算法验证 r 引导程序 模拟 重采样
2022-03-23 19:23:46

tl;dr:从在 null 下生成的数据集开始,我对带有替换的案例进行了重新采样,并对每个重新采样的数据集进行了假设检验。这些假设检验在超过 5% 的时间内拒绝零。

在下面非常简单的模拟中,我使用生成数据集,并为每个数据集拟合一个简单的 OLS 模型。然后,对于每个数据集,我通过使用替换对原始数据集的行进行重新采样来生成 1000 个新数据集(Davison & Hinkley 的经典文本中专门描述的适用于线性回归的算法)。对于其中的每一个,我都适合相同的 OLS 模型。最终,bootstrap 样本中大约 16% 的假设检验拒绝了 null,而我们应该得到 5%(就像我们在原始数据集中所做的那样)。XN(0,1)⨿YN(0,1)

我怀疑这与重复观察导致关联膨胀有关,因此为了比较,我在下面的代码中尝试了其他两种方法(已注释掉)。在方法 2 中,我修复 ​​,然后将替换为原始数据集上 OLS 模型的重采样残差。在方法 3 中,我绘制了一个没有放回的随机子样本。这两种选择都有效,即他们的假设检验在 5% 的时间里拒绝了零。XY

我的问题:重复观察是罪魁祸首,我说得对吗?如果是这样,鉴于这是一种标准的自举方法,我们究竟在哪里违反了标准的自举理论?

更新 #1:更多模拟

的仅截距回归模型出现同样的问题。Y

# note: simulation takes 5-10 min on my laptop; can reduce boot.reps
#  and n.sims.run if wanted
# set the number of cores: can change this to match your machine
library(doParallel)
registerDoParallel(cores=8)
boot.reps = 1000
n.sims.run = 1000

for ( j in 1:n.sims.run ) {

  # make initial dataset from which to bootstrap
  # generate under null
  d = data.frame( X1 = rnorm( n = 1000 ), Y1 = rnorm( n = 1000 ) )

  # fit OLS to original data
  mod.orig = lm( Y1 ~ X1, data = d )
  bhat = coef( mod.orig )[["X1"]]
  se = coef(summary(mod.orig))["X1",2]
  rej = coef(summary(mod.orig))["X1",4] < 0.05

  # run all bootstrap iterates
  parallel.time = system.time( {
    r = foreach( icount( boot.reps ), .combine=rbind ) %dopar% {

      # Algorithm 6.2: Resample entire cases - FAILS
      # residuals of this model are repeated, so not normal?
      ids = sample( 1:nrow(d), replace=TRUE )
      b = d[ ids, ]

      # # Method 2: Resample just the residuals themselves - WORKS
      # b = data.frame( X1 = d$X1, Y1 = sample(mod.orig$residuals, replace = TRUE) )

      # # Method 3: Subsampling without replacement - WORKS
      # ids = sample( 1:nrow(d), size = 500, replace=FALSE )
      # b = d[ ids, ]

      # save stats from bootstrap sample
      mod = lm( Y1 ~ X1, data = b ) 
      data.frame( bhat = coef( mod )[["X1"]],
                  se = coef(summary(mod))["X1",2],
                  rej = coef(summary(mod))["X1",4] < 0.05 )

    }
  } )[3]


  ###### Results for This Simulation Rep #####
  r = data.frame(r)
  names(r) = c( "bhat.bt", "se.bt", "rej.bt" )

  # return results of each bootstrap iterate
  new.rows = data.frame( bt.iterate = 1:boot.reps,
                         bhat.bt = r$bhat.bt,
                         se.bt = r$se.bt,
                         rej.bt = r$rej.bt )
  # along with results from original sample
  new.rows$bhat = bhat
  new.rows$se = se
  new.rows$rej = rej

  # add row to output file
  if ( j == 1 ) res = new.rows
  else res = rbind( res, new.rows )
  # res should have boot.reps rows per "j" in the for-loop

  # simulation rep counter
  d$sim.rep = j

}  # end loop over j simulation reps



##### Analyze results #####

# dataset with only one row per simulation
s = res[ res$bt.iterate == 1, ]

# prob of rejecting within each resample
# should be 0.05
mean(res$rej.bt); mean(s$rej)

更新#2:答案

评论和答案中提出了几种可能性,我做了更多的模拟来经验性地测试它们。事实证明,JWalker 是正确的,问题在于我们需要通过原始数据的估计来集中引导统计数据,以便在下获得正确的抽样分布。但是,我也认为 whuber 关于违反参数测试假设的评论也是正确的,尽管在这种情况下,当我们解决 JWalker 的问题时,我们实际上确实得到了名义上的误报。H0

4个回答

当您对空值重新采样时,回归系数的预期值为零。当您对某些观察到的数据集重新采样时,预期值是该数据的观察系数。如果在对观察到的数据重新采样时 P <= 0.05,则不是 I 型错误。实际上,如果 P > 0.05,则属于 II 型错误。

您可以通过计算 abs(b) 和 mean(P) 之间的相关性来获得一些直觉。这是复制您所做的更简单的代码,并在一组模拟中计算 b 和“I 型”错误之间的相关性

boot.reps = 1000
n.sims.run = 10
n <- 1000
b <- matrix(NA, nrow=boot.reps, ncol=n.sims.run)
p <- matrix(NA, nrow=boot.reps, ncol=n.sims.run)
for(sim_j in 1:n.sims.run){
  x <- rnorm(n)
  y <- rnorm(n)
  inc <- 1:n
  for(boot_i in 1:boot.reps){
    fit <- lm(y[inc] ~ x[inc])
    b[boot_i, sim_j] <- abs(coefficients(summary(fit))['x[inc]', 'Estimate'])
    p[boot_i, sim_j] <- coefficients(summary(fit))['x[inc]', 'Pr(>|t|)']
    inc <- sample(1:n, replace=TRUE)
  }
}
# note this is not really a type I error but whatever
type1 <- apply(p, 2, function(x) sum(x <= 0.05))/boot.reps
# correlation between b and "type I"
cor(b[1, ], type1)

通过 grand_chat更新答案不是 P <= 0.05 的频率 > 0.05 的原因。答案很简单,正如我上面所说的——每个重采样的平均值的期望值是原始的、观察到的平均值。这是 bootstrap 的全部基础,它的开发是为了在观察到的平均值上生成标准误差/置信限,而不是作为假设检验。由于期望不为零,当然“I 型错误”会大于 alpha。这就是为什么系数的大小(离零有多远)与“I 型错误”与 alpha 的偏差大小之间存在相关性的原因。

如果您从原始正常样本中替换样本,则生成的引导样本不是 normalbootstrap 样本的联合分布遵循一个很可能包含重复记录的粗糙混合分布,而当您从正态分布中获取 iid 样本时,重复值的概率为零。

举个简单的例子,如果您的原始样本是来自单变量正态分布的两个观测值,那么带替换的引导样本将一半时间由原始样本组成,一半时间将由一个原始值组成,重复。很明显,bootstrap 样本的样本方差平均会小于原始样本的样本方差——实际上它将是原始样本的一半。

主要后果是,您基于正常理论所做的推断在应用于引导样本时会特别是正常理论会产生反保守的决策规则,因为您的引导样本将产生个统计量,其分母小于正常理论下的预期,因为存在重复。结果,正态理论假设检验最终比预期更多地拒绝原假设。pt

我完全同意@JWalker 的回答。

这个问题还有另一方面。那是在您的重采样过程中。您期望回归系数以零为中心,因为您假设X并且Y是独立的。但是,在您重新采样时,您会

ids = sample( 1:nrow(d), replace=TRUE )
  b = d[ ids, ]

这会产生相关性,因为您正在采样XY在一起。例如,假设数据集的第一行d(x1, y1),在重新采样的数据集中,P(Y = y1|X = x1) = 1,而如果XY是独立P(Y|X = x1)的,则服从正态分布。

所以解决这个问题的另一种方法是使用

b = data.frame( X1 = rnorm( n = 1000 ), Y1 = rnorm( n = 1000 ) )

您用来生成的相同代码d,以使 X 和 Y 彼此独立。

同样的原因解释了为什么它适用于残差重采样(因为X独立于 new Y)。

这里最大的问题是模型结果是虚假的,因此非常不稳定,因为模型只是拟合噪声。从字面上看。由于样本数据的生成方式,Y1 不是因变量。


编辑,以回应评论。让我再次尝试解释我的想法。

使用 OLS 的一般目的是发现和量化数据中的潜在关系。对于真实世界的数据,我们通常不知道确切的数据。

但这是人为的测试情况。我们确实知道 EXACT 数据生成机制,它就在 OP 发布的代码中

X1 = rnorm(n = 1000),Y1 = rnorm(n = 1000)

如果我们用熟悉的 OLS 回归形式来表达,即

Y1 = 截距 + Beta1 * X1 + 误差
Y1
= mean(X1) + 0(X1) + Error

所以在我看来,这是一个以线性形式表示的模型,但它实际上不是线性关系/模型,因为没有斜率。Beta1=0.000000。

当我们生成 1000 个随机数据点时,散点图看起来就像经典的猎枪圆形喷雾。在生成的 1000 个随机点的特定样本中,X1 和 Y1 之间可能存在某种相关性,但如果是这样,那是随机事件。如果OLS 确实找到了相关性,即拒绝没有斜率的原假设,因为我们明确知道这两个变量之间确实没有任何关系,那么OLS 确实在误差分量中找到了模式。我将其描述为“拟合噪音”和“杂散”。

此外,OLS 的标准假设/要求之一是(+/-)“线性回归模型是“参数线性”。鉴于数据,我的看法是我们不满足该假设。因此,显着性的基础测试统计数据不准确。我认为违反线性假设是引导程序的非直观结果的直接原因。

当我第一次阅读这个问题时,它并没有因为 OP 打算在空 [假设] 下进行测试而陷入困境。

但是,如果数据集生成为

X1 = rnorm(n = 1000),Y1 = X1*.4 + rnorm(n = 1000)?