R boot包boot()函数如何同时返回bootstrap均值及对应抽样样本
boot()函数内部会预先创建名为t.star的矩阵,用来按行存储每次重抽样计算得到的统计量值,因此要求用户传入的统计量计算函数必须返回固定长度的数值型向量。
你编写的函数返回的是同时包含均值、重抽样样本的列表,返回值类型、结构都不符合boot()对统计量返回值的要求,给矩阵赋值时维度和类型无法匹配,就会触发如下报错:
Error in t.star[r, ] <- res[[r]] : incorrect number of subscripts on matrix
另外boot包默认不存储全量重抽样样本,是因为当迭代次数R、原始样本量较大时,存储所有重抽样样本会占用极高的内存,属于非必要的冗余设计。
推荐使用官方提供的接口提取重抽样索引,不需要修改统计函数的标准返回格式,也不会产生全局环境的副作用,是最稳妥的方案:
方案1:通过boot.array提取索引后自行生成样本(推荐)
boot包内置了boot.array()函数,可以直接从运行完成的boot对象中提取每次重抽样的位置索引,你只需要正常运行bootstrap流程,之后用索引匹配原始数据就能得到每个均值对应的重抽样样本:
library('boot') # 保持统计函数的标准写法,仅返回需要计算的统计量(均值) boot_mean <- function(data, i){ ds_m <- data[i] return(mean(ds_m)) } dummy_data <- rnorm(500) set.seed(123) # 设置随机种子保证结果可复现 dummy_boot <- boot(dummy_data, boot_mean, R = 1000) # 提取1000次重抽样的索引矩阵:每行对应当次重抽样抽取的原始数据位置 boot_index_mat <- boot.array(dummy_boot, indices = TRUE) # 遍历索引生成对应的重抽样样本列表 boot_sample_list <- lapply(1:nrow(boot_index_mat), function(r){ dummy_data[boot_index_mat[r, ]] }) # 验证对应关系:第一组样本计算的均值和boot输出的第一个均值完全一致 mean(boot_sample_list[[1]]) == dummy_boot$t[1]
运行后boot_sample_list中存储的1000个样本,和dummy_boot$t中存储的1000个bootstrap均值按顺序一一对应。
方案2:运行过程中通过外部容器存储样本
如果需要在bootstrap运行过程中同步拿到样本,可以在全局环境初始化存储容器,在统计函数内用全局赋值符将重抽样样本存入容器,注意统计函数本身仍然只返回数值型的统计量值,避免触发格式报错:
library('boot') # 提前初始化和迭代次数等长的列表存储样本 boot_sample_list <- vector("list", 1000) # 初始化迭代计数器 iter_count <- 1 boot_mean <- function(data, i){ ds_m <- data[i] # 将当前重抽样样本存入列表对应位置 boot_sample_list[[iter_count]] <<- ds_m # 计数器自增 iter_count <<- iter_count + 1 # 仅返回数值型均值,符合boot返回要求 return(mean(ds_m)) } dummy_data <- rnorm(500) set.seed(123) dummy_boot <- boot(dummy_data, boot_mean, R = 1000)
这个方法需要注意全局变量的污染问题,如果要多次运行bootstrap,需要提前重置存储列表和计数器,避免结果错位。
内容的提问来源于stack exchange,提问作者Corbjn

