【问题标题】:How to optimize 2 loops如何优化 2 个循环
【发布时间】:2011-12-12 22:01:02
【问题描述】:

我正在运行一个模拟,试图找出在一些二项式试验中发生某事的概率。我从指定数据开始

iter=5000
data=data.frame(prob=runif(300), value=runif(300))
data<-data[sample(nrow(data), iter, replace=T),]

然后我添加试验

cols <- c("one","two","three","four","five","six",
          "seven","eight","nine","ten","eleven","twelve")
data[,cols] <- NA

one 只包含一个二项式试验的结果,two 包含两个二项式试验的结果,依此类推。如果在onetwothree、...、twelve 中的任何一个中发生二项式事件,则该单元格标记为 1,否则标记为 0。

然后我运行iter=5000 模拟的试验

for (col in 3:14) {
  for (i in 1:iter) if (sum(rbinom((col-2),1,data[i,1]))>0) data[i,col]<-1 else data[i,col]<-0
}

然后我评估 mean(data$value[data$one==0] 直到 ... mean(data$value[data$twelve==0]

我的问题是iter&gt;15000 的模拟代码需要很长时间。

  for (col in 3:14) {
    for (i in 1:iter)
      data[i,col] <- if (sum(rbinom((col-2),1,data[i,1]))>0) 1 else 0
  }

有什么想法吗?

【问题讨论】:

  • 我在上面运行你的第一个双循环时出错:Error in if (sum(rbinom((col - 2), 1, data[i, 1])) &gt; 0) 1 else 0 : missing value where TRUE/FALSE needed
  • 还可以查看if...else 的矢量化版本。该函数名为ifelse()。我很难理解你想用这段代码做什么,但我几乎可以向你保证,我们可以摆脱至少一个 for 循环,如果不能同时使用矢量化解决方案,运行速度会更快。
  • prob 必须是 runif(300),而不是 rnorm(300),因为这是一个概率。
  • 您的算法在iter 中似乎是 O(n^2)。不过,我不确定为什么,因为iter 上只有一个循环。我猜这与复制数据有关。从我运行的时间推断,15000 将花费我的计算机大约半小时。
  • 对不起,伙计们。我的错。我更正了代码并运行正常,但速度很慢。我需要在一个非常大的集合上执行此操作,大约 500.000 并且多次。

标签: r


【解决方案1】:
sim2 <- function(iter) {
    dat <- data.frame(prob=runif(300), value=runif(300))
    dat <- dat[sample(nrow(dat), iter, replace=TRUE),]
    cols <- c("one","two","three","four","five","six",
              "seven","eight","nine","ten","eleven","twelve")
    dat[,cols] <- 0

    for (col in 3:14) {
        dat[,col] <- as.numeric(vapply(dat[,1],
                                       function(p) {sum(rbinom((col-2), 1, p))>0},
                                       FUN.VALUE = TRUE))
    }
    vapply(3:14, function(col) {mean(dat$value[dat[,col]==0])}, FUN.VALUE=1)
}

对于 16000 的 iter,这在我的机器上运行时间为 2.29 秒,而原始算法中的排序(估计)为 1781 秒。通常,当您可以一次分配整个列时,不要在数据框中分配单个元素。可能会有更多改进,但我将停止在 >750x 加速(并将算法从 O(n^2) 的运行时间更改为 O(n))。

【讨论】:

    猜你喜欢
    • 2011-04-28
    • 2011-05-30
    • 2019-03-21
    • 1970-01-01
    • 2021-07-10
    • 2011-06-15
    • 1970-01-01
    • 2022-11-03
    相关资源
    最近更新 更多