在 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
这是一个关于将 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