样品的替代品

Alternative for sample

我有以下 sample 使用 sapply 的代码,需要很长时间才能处理(因为执行了很多次):

samples = sapply(rowIndices, function(idx){
  sample(vectorToDrawFrom, 1, TRUE, weights[idx, ])
})

问题是我必须根据 rowIndices 中的索引从矩阵中的权重中提取。

有人有更好的想法从矩阵的行中提取吗?

可重现的例子:

rowIndices = floor(runif(1000, 1, 100))
vectorToDrawFrom = runif(5000, 0.0, 2.0)
weights = matrix(runif(100 * 5000, 1, 10), nrow = 100, ncol = 5000)

timer = 0
for (i in 1:2500){
  ptm = proc.time()
  samples = sapply(rowIndices, function(idx){
    sample(vectorToDrawFrom, 1, TRUE, weights[idx, ])
  })
  timer = timer + (proc.time() - ptm)[3]
}

print(timer) # too long!!

所以这是我可以加速您的代码的方法。需要注意的一件事:采样值不会 "match" 与 rowIndices 尽管按正确的顺序获取事物是微不足道的。 2) 你只存储最后一次迭代,虽然这可能只是因为这是一个最小可重现的例子......

基本上每个 rowIndices 的值只需要调用 sample 一次,因为 rowIndices 的范围是 1-99,即调用 99 次而不是 1000 次,这提供了巨大的速度向上。

我们可以在开始之前对行索引进行排序

rowIndices <- sort(rowIndices) ##sort the row indices and then loop
for (i in 1:15){
    samples = unlist(sapply(unique(rowIndices), 
        function(idx){
            sample(vectorToDrawFrom, sum(rowIndices %in% idx), 
                TRUE, weights[idx, ])
    }))       
}

Unit: milliseconds

expr
                      min       lq     mean   median       uq      max neval cld
 newForLoop      263.5668 266.6329 292.8301 268.8920 275.3378  515.899   100  a 
 OriginalForLoop 698.2982 705.6911 792.2846 712.9985 887.9447 1263.779   100   b

编辑

保持原始向量排序的方法是保存索引或原始rowIndices向量。然后对行索引进行排序并继续。

set.seed(8675309)
weights = matrix(c(1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0), 
                 nrow = 5, ncol = 3, byrow = T)

rowIndices = c(2,1,2,4)
vectorToDrawFrom = runif(3, 0.0, 2.0)

set.seed(8675309)
##This is the origal code
sample2 = sapply(rowIndices, function(idx){       
  sample(vectorToDrawFrom, 1, TRUE, weights[idx, ])
})

rowIndx <- order(rowIndices)   #get ordering index
rowIndices <- sort(rowIndices) 

set.seed(8675309)
samples = unlist(sapply(unique(rowIndices), function(idx){
  sample(vectorToDrawFrom, sum(rowIndices %in% idx), TRUE, weights[idx, ])
}))

samples = samples[order(rowIndx)]
all(samples == sample2)
#[1] TRUE