【问题标题】:Improving loop speed (apply doesn't help)提高循环速度(应用没有帮助)
【发布时间】:2018-08-06 04:22:46
【问题描述】:

我需要加快我正在执行的模拟,我发现我的一个函数的特定组件是造成速度如此缓慢的主要原因。

这部分函数的工作是演示从分布中增加随机抽奖的数量 (n) 如何提高该组抽奖的平均估计精度。

程序如下:

  • 样本 n 从具有固定参数 musigma 的正态分布中随机抽取,其中 n 从1 到 500。(在本例中,我只设置 mu = 500 和 sigma = 100。)
  • 在每个 n 处,计算所有采样值的平均值
  • 重复此过程 1000 次。

我目前在嵌套循环中使用它,我知道它效率不高。代码如下:

# generate empty container for the simulated data
# parameters: 
# n_repetition = how many times to repeat the whole procedure
# max_n = maximum number of draws to explore

set.seed(42)
n_repetition <- 1000
max_n <- 500

# function to generate n random draws, and find their mean
r_norm <- function(n, mean, sd){
 temp <- rnorm(n, mean, sd)
 return(mean(temp))
}

sim_results <- matrix(0, nrow = n_repetition, ncol = max_n)

for(i in 1:n_repetition){
 for(j in 1:max_n){
   sim_results[i, j] <- r_norm(j, mean = 500, sd = 100)
 }
}

这很慢;在我的机器上大约 9.80 秒。因此,我尝试使用“应用系列”方法。事实证明这同样慢:

sim_results <- matrix(1:max_n, nrow = max_n, ncol = n_repetition)
sim_results <- apply(sim_results, 1:2, r_norm, mean = 500, sd = 100)

我不确定如何继续。我认为 R 中的减速是循环,但我使用“应用”删除了它,它同样慢。

我什至想不出如何让它更快,所以非常感谢任何帮助。

【问题讨论】:

  • Apply 仍在循环中,它只是隐藏了循环,因此您不必自己编写。这是您正在做的一个非常简单的程序 - 没有太多工作可以加快速度。您可以直接调用.Internal(mean()) 而不是mean() 来减少几微秒的调度和输入检查,但在不到10 秒的时间内完成500k 次模拟似乎并不算太​​糟糕。为什么你需要这个更快?你是否经常重新模拟这个?你需要那里的每一个j吗?获得 10 倍加速的简单方法是将 j 运行为 seq(10, max_n, by = 10) 而不是 1:max_n
  • 谢谢@Gregor。不幸的是,我确实需要那里的每一个 j。我试图简化我的完整模拟背后的想法,以专注于这个问题。对于传递给采样分布的每个组参数值(64 个参数变体),上述过程可能会重复 1000 次。这意味着完整的模拟将需要大约一周的时间。
  • 而不是每次重复生成 500 组不同的随机数。尝试生成一组 500 个数字并使用列表中的 cummean 函数。然后为下一次重复生成一个新集合。
  • 您的apply 与您的循环不同,您翻译了您的矩阵并且您没有在apply 中使用mean,因此每个单元格值都是一个向量。你可能想要apply(sim_results, 1:2, function(x) mean(rnorm(x), mean = 500, sd = 100))
  • 我建议你看看是随机抽签还是瓶颈所在。我的猜测是采取手段至少比从您的分布中随机抽取快一个数量级,这意味着获得大幅加速的唯一方法是减少抽取次数(或提高抽取速度)。 Dave2e 的建议,单抽 500 分并在上面使用cummean 是一个非常好的建议,如果您对此方法满意的话。

标签: r


【解决方案1】:

根据我上面的评论。现有的嵌套 for 循环为每次重复生成一组新的随机数。一个改进是每次重复生成一组随机数,并使用内置的cummean函数。

下面的代码显示了原始代码和改进后的比较。原始代码耗时约 13 秒,改进约 1 秒。

print(Sys.time())
set.seed(42)
n_repetition <- 1000
max_n <- 500

sim_results <- matrix(0, nrow = n_repetition, ncol = max_n)

for(i in 1:n_repetition){
  for(j in 1:max_n){
    sim_results[i, j] <- mean(rnorm(j, mean = 500, sd = 100))
  }
}

print(Sys.time())
sim_results2 <- matrix(0, nrow = n_repetition, ncol = max_n)
set.seed(42)
for(i in 1:n_repetition){
    sim_results2[i, ] <- cummean(rnorm(max_n, mean = 500, sd = 100))

}
print(Sys.time())

【讨论】:

  • 这真的很棒。我刚刚在我的完整模拟中尝试过,它大大减少了一次扫描的时间。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-24
  • 1970-01-01
  • 2019-08-01
  • 2014-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多