R语言处理缺失数据:Bootstrap与Jackknife插补前后对比

Elena
Elena
发布时间:2026-10-16| 7人浏览过
原创

在处理含有缺失值的数据集时,直接删除缺失项或统一填补缺失后再进行重抽样(如Bootstrap)往往会掩盖数据的不确定性并引入偏差。本文通过R语言构建模型,对比了“先填补后重抽样”与“先重抽样再局部填补”两种策略在均值和变异系数估计上的表现,证明了后者在缩小标准差和提高置信区间覆盖率方面的优势。

核心结论

在缺失数据场景中,统计推断的准确性高度依赖于处理缺失值的时机。模拟实验表明:

  • 填补前重抽样(推荐):在Bootstrap或Jackknife的每一次迭代中,仅使用当前子样本进行数据填补,能有效保留数据的变异性,显著减小估计方差,90%置信区间的覆盖效果更好。
  • 填补后重抽样(不推荐):若先用完整数据集填补缺失值,再对填充后的数据进行重抽样,由于引入了插补模型的偏差且未反映缺失不确定性,会导致估计结果偏离真实值更远,波动性更大。

数据生成与问题定义

为了验证上述假设,我们需要构造一个包含特定机制缺失值的数据集。题目设定如下变量关系:

其中参数 a=2, b=0,用于控制第三列变量的缺失机制。真实的目标是估计第二列变量(y2)的均值与变异系数。

实现步骤详解

第1步:构建数据生成函数

目的是重现含有随机缺失(Missing at Random, MAR)特性的数据集。我们通过线性关系生成观测值,并依据残差条件判断是否将部分数据标记为 NA。

# GenerateData <- function(a = 0, b = 0) {
#   y <- matrix(nrow = 3, ncol = 100)
#   z <- matrix(rnorm(300), nrow = 3)
# 
#   y[1, ] <- 1 + z[1, ]
#   y[2, ] <- 5 + 2 * z[1, ] + z[2, ]
# 
#   u <- a * (y[1, ] - 1) + b * (y[2, ] - 5) + z[3, ]
# 
#   y[3, ] <- y[2, ]
#   y[3, u < 0] <- NA
# 
#   dat_comp <- data.frame(y1 = y[1, ], y2 = y[2, ])     # 完整数据
#   dat_incomp <- data.frame(y1 = y[1, ], y2 = y[3, ])  # 含缺失数据
#   return(list(dat_comp = dat_comp, dat_incomp = dat_incomp))
# }

此函数返回两个数据框:dat_comp 为无缺失的真实数据,dat_incomp 为实际观察到的含缺失数据。

第2步:编写基础重抽样函数

分别实现基础的 Bootstrap(有放回抽样)和 Jackknife(留一法)逻辑,用于后续对比不同场景下的统计量(如均值、标准差)。

# Bootstrap: B为重复次数,fun为重抽样计算函数
Bootstrap1 <- function(Y, B = 200, fun) {
  Y_len <- length(Y)
  mat_boots <- matrix(sample(Y, Y_len * B, replace = T), nrow = B, ncol = Y_len)
  statis_boots <- apply(mat_boots, 1, fun)
  boots_mean <- mean(statis_boots)
  boots_sd <- sd(statis_boots)
  return(list(mean = boots_mean, sd = boots_sd))
}

# Jackknife: 剔除第i个样本
Jackknife1 <- function(Y, fun) {
  Y_len <- length(Y)
  mat_jack <- sapply(1:Y_len, function(i) Y[-i])
  redu_samp <- apply(mat_jack, 2, fun)
  jack_mean <- mean(redu_samp)
  jack_sd <- sqrt(((Y_len - 1) ^ 2 / Y_len) * var(redu_samp))
  return(list(mean = jack_mean, sd = jack_sd))
}

第3步:执行线性填补策略 (After Imputation)

这是传统做法:先在完整观测数据上训练线性回归模型预测缺失值,填补完成后,再对填充好的数据进行 Bootstrap 或 Jackknife。

填补逻辑:

DatImputation <- function(dat_incomp) {
  dat_imp <- dat_incomp
  # 使用非缺失数据建立 y2 ~ y1 模型
  lm_model <- lm(y2 ~ y1, data = na.omit(dat_incomp))
  na_ind <- is.na(dat_incomp$y2)
  if(any(na_ind)) {
    na_dat <- dat_incomp[na_ind, ]
    dat_imp[na_ind, 'y2'] <- predict(lm_model, na_dat)
  }
  return(dat_imp)
}

# 应用举例
# dat <- GenerateData(a = 2, b = 0)
# dat_imp <- DatImputation(dat$dat_incomp)
# Bootstrap1(dat_imp$y2, B = 200, mean)$sd  # 填补后Bootstrap

问题分析:这种做法忽略了填补值本身的不确定性,使得方差估计偏小或产生系统性偏差。

第4步:执行重抽样伴随填补策略 (Before Imputation)

改进策略:在Bootstrap或Jackknife抽取子样本后,再对该子样本单独进行线性填补,最后计算统计量。这样能保证每次重抽样都反映了该子样本特有的填补不确定性。

组合函数逻辑:

# 针对某个子样本数组进行填补并计算均值(CV)
Array2meancv <- function(j, myarray) {
  dat_incomp <- as.data.frame(myarray[, j, ])   # 提取第j次抽样/留样
  names(dat_incomp) <- c('y1', 'y2')
  # 在该子样本内部重新拟合并填补
  dat_imp_temp <- DatImputation(dat_incomp)
  
  y2_val <- dat_imp_temp$y2
  return(c(mean = mean(y2_val), cv = sd(y2_val)/mean(y2_val)))
}

# Bootstrap带填补版本
Bootstrap_imp <- function(dat_incomp, B = 200) {
  n <- nrow(dat_incomp)
  array_boots <- array(dim = c(n, B, 2))
  mat_boots_ind <- matrix(sample(1:n, n * B, replace = T), nrow = B, ncol = n)
  
  # 构建B个子样本矩阵
  array_boots[, , 1] <- sapply(1:B, function(i) dat_incomp$y1[mat_boots_ind[i, ]])
  array_boots[, , 2] <- sapply(1:B, function(i) dat_incomp$y2[mat_boots_ind[i, ]])
  
  mean_cv_imp <- sapply(1:B, Array2meancv, array_boots)
  return(list(
    mean = apply(mean_cv_imp, 1, mean),
    sd = apply(mean_cv_imp, 1, sd)
  ))
}

第5步:比较置信区间覆盖率 (CI Coverage)

为了量化哪种方法更好,我们进行重复模拟实验,检查计算出的均值或变异系数的 90% 置信区间是否包含真实值(已知真实均值约为5,真实CV约为 sqrt(5)/5)。

判断逻辑:

通过多次运行 RepSimulationCI 并统计命中次数(即数字越大越好),得出以下对比结果:

结果分析与理论解释

模拟实验的汇总数据显示(重复100次):

  • 填补前进行Bootstrap/Jackknife:其标准差估计更接近大样本解析解(0.037左右),且置信区间覆盖真实值的比例更高。
  • 填补后进行Bootstrap/Jackknife:估计偏差较大,置信区间覆盖率低。

原理阐释:

当缺失近半数据时,统一填补会将整个数据集“硬化”,丢失了缺失部分的随机特征。随后从中采样,极易抽到大量已被过度拟合填补值的样本,导致方差低估。相反,“先抽样再填补”相当于将插补过程作为重抽样方差的一部分进行了积分,能够更真实地反映总体参数的估计不确定性。

总结

在使用 R 语言处理带有缺失值的数据并进行重抽样检验时,务必注意插补操作的重合时机。不要在清洗阶段完成全局插补后再做 Bootstrap,而应当在每一次 Bootstrap 迭代内部动态地进行局部插补。虽然这种方法计算成本稍高,但能显著提升统计推断的有效性和稳健性。

以上就是R语言学习笔记缺失数据的Bootstrap与Jackknife方法的详细内容,更多关于R语言缺失数据处理、统计分析的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。