提高自举功能的效率

Improve efficiency of bootstrap function

提问人:heikeehee 提问时间:11/16/2023 更新时间:11/17/2023 访问量:38

问:

我有一个大数据帧,我想从中对每列进行随机抽样。我想多次采样并将结果的总和存储在新的数据帧中。

我的数据帧如下所示:

library(microbenchmark)
library(plyr)
library(tidyverse)

set.seed(123)
df <- data.frame(matrix(sample(0:10, replace = T), nrow = 1000, ncol=60))

我编写了一个函数来从我的数据帧中采样并计算我的统计数据。

rd <- function(x) sample(x, size = N, replace =TRUE)
N <- nrow(df)

sampling <- function(df){
  df_s <- apply(df, 2, rd) 
  
  df_f <- df_s %>% 
    as.data.frame() %>%
    summarise_if(is.numeric, sum)
  }

我想复制这 10000 并将汇总统计信息保存在新的数据帧中。

reps <- 10
df_sums <- plyr::rdply(reps, sampling(df))

但是,单独运行此代码 100 次似乎效率非常低,使用我的原始数据集需要更长的时间。

microbenchmark(sampling(df), times = 100)

有什么建议如何使它更有效率,以便我可以实际运行我的代码 10000 次?我尝试用 编写函数,但我无法让输出看起来像 一样整洁。replicaterdply

R Plyr 示例 启动 微基准测试

评论


答:

0赞 Robert Hacken 11/16/2023 #1

也许您不需要对单个列重新采样,但可以一次对整个数据帧进行重新采样。

sampling2 <- function(df) {
  colSums(df[sample(nrow(df), replace=T), ])
}
df_sums <- t(replicate(100, sampling2(df)))

这工作得更快:

microbenchmark(sampling(df),
               sampling2(df))
# Unit: milliseconds
#          expr       min        lq      mean    median        uq      max neval cld
#  sampling(df) 62.047601 64.451151 77.350142 69.629501 81.000350 476.3357   100   b
# sampling2(df)  1.427401  1.562552  1.954756  1.654052  1.906201  13.3865   100  a 

请注意,使用这种方法会在一定程度上破坏 行中值的独立性。如果这将是一个问题,可以通过重新采样以下列来解决:df_sumsdf_sums

df_sums <- apply(df_sums, 2, sample)

评论

0赞 jblood94 11/17/2023
这些样本在各列之间不会独立,例如,第一列的第 1 个值将始终与第二列的第 1 个值一起采样。
0赞 Robert Hacken 11/17/2023
@jblood94 没错,如果这对 OP 的应用程序来说是一个问题,他们总是可以对结果矩阵的行进行重采样。我可能应该更明确地说明这一点,谢谢!
0赞 heikeehee 11/17/2023
是的,我应该更清楚这一点(我希望我的代码正在这样做)。我想从每一列中随机抽取样本,这些样本独立于其他列,也独立于从中抽样的行。
0赞 jblood94 11/17/2023 #2

由于它是用替换进行采样的,因此您可以用内存换取速度。取 10k bootstrap 样本乘以每列的 1k 行 = 10M 样本,将它们放入 10k×1k 矩阵中并取行总和。示例矩阵在我 8 岁的笔记本电脑上需要 30 秒。

set.seed(123)
df <- data.frame(matrix(sample(0:10, 6e4, 1), 1e3, 60))

library(Rfast)

system.time(
  sapply(df, \(x) rowsums(matrix(sample(x, 1e4*length(x), 1), 1e4)))
)
#>    user  system elapsed 
#>   27.12    1.06   30.47