在 R 中将 boot::boot() 函数与分组变量一起使用

Using boot::boot() function with grouped variables in R

这是一个关于将 boot() 函数与分组变量一起使用的问题,也是关于将多列数据传递到 boot.几乎所有 boot() 函数的示例似乎都传递单列数据来计算简单的 bootstrap 均值。

我的具体分析是尝试使用 stats::weighted.mean(x,w) 函数,该函数采用值的向量 'x' 来计算平均值和第二个向量 'w'对于权重。要点是我需要两个输入到这个函数中——我希望这个解决方案可以推广到任何接受多个参数的函数。

我也在寻找一种解决方案,以便在具有 group_by() 变量的 dplyr 样式工作流中使用此 weighted.means 函数。如果答案是 “它不能用 dplyr 完成”,没关系,我只是想弄明白。

下面我模拟了一个包含三组(A、B、C)的数据集,每组都有不同的计数范围。我还尝试提出一个函数“my.function”,它将用于 bootstrap 加权平均值。这可能是我的第一个错误:这就是我设置函数以将 'count' 和 'weight' 列数据传递到每个 bootstrapped 样本的方式吗?有没有其他方法来索引数据?

在 summarise() 调用中,我用“.”引用了原始数据。 - 可能是另一个错误?

最终结果表明我能够使用 mean() 和 weighted.mean() 实现适当的分组计算,但是使用 boot() 的置信区间调用反而计算了大约 95% 的置信区间数据集的全局平均值。

关于我做错了什么的建议?为什么 boot() 函数引用整个数据集而不是分组的子集?

library(tidyverse)
library(boot)


set.seed(20)

sample.data = data.frame(letter = rep(c('A','B','C'),each = 50) %>% as.factor(),
                         counts = c(runif(50,10,30), runif(50,40,60), runif(50,60,100)),
                         weights = sample(10,150, replace = TRUE))



##Define function to bootstrap
  ##I'm using stats::weighted.mean() which needs to take in two arguments

##############
my.function = function(data,index){

  d = data[index,]  #create bootstrap sample of all columns of original data?
  return(weighted.mean(d$counts, d$weights))  #calculate weighted mean using 'counts' and 'weights' columns
  
}

##############

## group by 'letter' and calculate weighted mean, and upper/lower 95% CI limits

## I pass data to boot using "." thinking that this would only pass each grouped subset of data 
  ##(e.g., only letter "A") to boot, but instead it seems to pass the entire dataset. 

sample.data %>% 
  group_by(letter) %>% 
  summarise(avg = mean(counts),
            wtd.avg = weighted.mean(counts, weights),
            CI.LL = boot.ci(boot(., my.function, R = 100), type = "basic")$basic[4],
            CI.UL = boot.ci(boot(., my.function, R = 100), type = "basic")$basic[5])

下面我计算了围绕全球平均值的 95% 置信区间的粗略估计,以表明这就是我在上面的 summarise() 调用中使用 boot() 发生的情况

#Here is a rough 95% confidence interval estimate as +/-  1.96* Standard Error


mean(sample.data$counts) + c(-1,1) * 1.96 * sd(sample.data$counts)/sqrt(length(sample.data[,1]))



以下基本 R 解决方案解决了按组引导的问题。请注意 boot::boot 仅调用一次。

library(boot)

sp <- split(sample.data, sample.data$letter)
y <- lapply(sp, function(x){
  wtd.avg <- weighted.mean(x$counts, x$weights)
  basic <- boot.ci(boot(x, my.function, R = 100), type = "basic")$basic
  CI.LL <- basic[4]
  CI.UL <- basic[5]
  data.frame(wtd.avg, CI.LL, CI.UL)
})

do.call(rbind, y)
#   wtd.avg    CI.LL    CI.UL
#A 19.49044 17.77139 21.16161
#B 50.49048 48.79029 52.55376
#C 82.36993 78.80352 87.51872

最后清理:

rm(sp)

dplyr 解决方案可能如下所示。它还从包 purrr.

调用 map_dfr
library(boot)
library(dplyr)

sample.data %>%
  group_split(letter) %>% 
  purrr::map_dfr(
    function(x){
      wtd.avg <- weighted.mean(x$counts, x$weights)
      basic <- boot.ci(boot(x, my.function, R = 100), type = "basic")$basic
      CI.LL <- basic[4]
      CI.UL <- basic[5]
      data.frame(wtd.avg, CI.LL, CI.UL)
    }
  )
#   wtd.avg    CI.LL    CI.UL
#1 19.49044 17.77139 21.16161
#2 50.49048 48.79029 52.55376
#3 82.36993 78.80352 87.51872