首页 > 解决方案 > 替代 mapply 选择样本

问题描述

我创建了一个mapply函数来从数据集中选择样本,但是有没有更快的方法来避免mapply因为它很慢而且我有一个更大的数据集?我的目标是使用更多的矩阵/向量运算,而更少的列表。

#A list of a set of data to be selected
bl <- list(list(c(1, 2),c(2, 3), c(3, 4), c(4, 5), c(5, 6), c(6, 7), c(7, 8), c(8, 9)), 
           list(c(1, 2, 3), c(2, 3, 4), c(3, 4, 5), c(4, 5, 6), c(5, 6, 7), c(6, 7, 8)), 
           list(c(1, 2, 3, 4, 5), c(2, 3, 4, 5, 6), c(3, 4, 5, 6, 7), c(4, 5, 6, 7, 8), c(5, 6, 7, 8, 9)))
#Number of elements to be selected
kn <- c(5, 4, 3)
#Total number of elements in each set
nb <- c(8, 6, 5)
#This output a list but preferably I would like a matrix 
bl_func <- function() mapply(function(x, y, z) {
  x[sample.int(y, z, replace = TRUE)]
}, bl, nb, kn, SIMPLIFY = FALSE)

编辑 正如@LMc 所建议的,parallel::mcmapply确实更快:

mc.cores=parallel::detectCores()-1
bl_func <- function() parallel::mcmapply(function(x, y, z) {
  x[sample.int(y, z, replace = TRUE)]
}, bl, nb, kn, SIMPLIFY = FALSE)

bl_func.0 <- function() mapply(function(x, y, z) {
  x[sample.int(y, z, replace = TRUE)]
}, bl, nb, kn, SIMPLIFY = FALSE)

library(microbenchmark)
microbenchmark(
  para = bl_func(),
  nopara = bl_func.0(),
  times = 100
)
Unit: microseconds
   expr      min       lq  mean  median    uq   max neval
   para 11601.12 18176.46 19901 20402.4 21872 26457   100
 nopara    37.34    90.86  1275   246.5  1311  9159   100

不过,我仍然很好奇在没有并行过程帮助的情况下加快速度的其他方法。任何想法将不胜感激!

标签: roptimizationdata-manipulationsamplemapply

解决方案


使用专为速度和大型数据集设计的工具,例如data.table

要做到这一点,您需要将数据从列表重塑data.table为无论如何都是一个好主意。

这是一个尝试:

require(data.table)

x = lapply(bl, function(x) data.table( t(data.frame(x) ) ) )
x = lapply(x, melt)
for( i in 1:length(x) ) x[[i]][, group := i]
x = rbindlist(x)

现在,列表的原始列表由data.table3 列构成: value包含实际数据、variable定义每个列表中的向量以及group定义列表 ID。

> head(x)
   variable value group
1:       V1     1     1
2:       V1     2     1
3:       V1     3     1
4:       V1     4     1
5:       V1     5     1
6:       V1     6     1

data.table有一个by参数,这意味着我们可以.SD按一列或多列对行 () 进行采样,data.table如下所示:

x[,.SD[ sample(  .N, sample(nb,1) , replace = TRUE )   ],by = group ]
    group variable value
 1:     1       V2     6
 2:     1       V2     5
 3:     1       V1     6
 4:     1       V1     7
 5:     1       V1     3


推荐阅读