【问题标题】:Alternative for sample样品的替代品
【发布时间】:2017-10-16 13:10:32
【问题描述】:

我有以下使用sapplysample 代码需要很长时间来处理(因为执行了很多次):

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!!

【问题讨论】:

  • sapply 真的是瓶颈吗?我对此表示怀疑。
  • 是的,因为它被执行了数千次。
  • 查看我更新的问题
  • 我的意思是 你的 sapply 里面的东西 可能是瓶颈。不使用sapply 本身。如果你不能加快随机抽样(或者你实际代码中的任何东西),你就是在浪费你的时间。
  • 加快sample 的一种方法是调用一次并绘制n 次。我的意思是rowIndices 平均被复制了 10 倍。不要为同一行索引调用 sample 10 次,而是调用 sample 一次并绘制 10 个值(或者您需要的任意多个值)。这使我的测试速度提高了 5 倍

标签: r loops sapply


【解决方案1】:

所以这是我加快代码速度的一种方法。需要注意的一件事:采样值不会与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

【讨论】:

  • 很好的建议。但是,我需要rowIndices 的“匹配”。你说保持匹配很简单?你将如何进行?
  • 不,排序不起作用。例如 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)。只有第一个返回值才能成为vectorToDrawFrom[2]
  • 我认为结果是正确的,我这里用你的例子来尝试说明
  • 为了满足我的需要,结果应该是[1] 1.9971544 1.2770329 1.9971544 0.3762992。我需要rowIndices 的原始顺序,因为之后我要与矩阵相乘。
  • order 的好建议。但是,它仍然不起作用,并且它适用于您的示例似乎是您设置的数据和种子的人工制品。要查看它不太有效,请参阅此示例,我在其中随机选择所有内容:paste.ofcode.org/AeH5MtmDAnRNKyceVbg6jZ
猜你喜欢
  • 2011-08-29
  • 1970-01-01
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 2014-04-29
  • 2011-06-10
  • 2014-04-18
  • 2012-04-08
相关资源
最近更新 更多