【问题标题】:Improve Excecution Time of For Loop by Replacing it with lapply command通过用 lapply 命令替换 For 循环来改进它的执行时间
【发布时间】:2019-06-16 17:17:45
【问题描述】:

这里我正在优化 R-code ,众所周知,最耗时的是 for loop ,我正在尝试用 lapply 替换它并进行实验以减少执行时间。

从图中可以看出,执行 for 循环所需的时间为 40 毫秒,这里的任务是如何通过使用 lapply 来最小化 For 循环的执行时间。 How to replace this code of for loop with Lapply 这样我们可以有效的优化代码的处理速度。为了确定每一行代码库 Profvis 所需的时间。 我试过使用 lapply ,我在实施中遇到了问题

library(profvis)
profvis({
rm(list = ls())
# Creating Dummy data 
row_id <- 100
No_of_level <- 4
spliz <- paste("c(","TRUE,",paste(rep("FALSE",(row_id-1)),collapse=","),")")
d <- as.data.frame(matrix(,nrow = row_id*No_of_level ,ncol=2))
names(d) <- c("Tag","y_pred")
d$Tag <-  cumsum(rep(eval(parse(text=spliz)),4))
d$y_pred <- sample(3:4, row_id*No_of_level, rep = TRUE)
d$y_pred <- paste("L",d$y_pred,sep="")
#### ------------------------------------

# How to replce Below For Loop codes to lapply and get the result in the variable.     
    v <- data.frame();i=0
    for (i in (1:max(d$Tag))){
      #i=4
      s <- filter(d , Tag == i)
s$y_pred <- as.character(s$y_pred)
      temp = 0
      for(i in 1:nrow(s))
      s$R2[i] <- ifelse(s$y_pred[i] == "L3", temp <- temp + 1, 0)
      s$seq <- seq_along(1:nrow(s))
      s$Aoc <- (1-(s$R2/s$seq))*100
      s$Aoc1 <- (s$R2/s$seq)
      v <- rbind(v,s)
  }

})

预期: 改进上述 For 循环代码的执行时间,执行时间为 40 毫秒,如果我们尝试使用 lapply 可能我们可以将处理时间从 40 毫秒提高到 10 毫秒或少于那个。

【问题讨论】:

  • 我不认为 lapply 比 for 循环快得多。它基本上只是循环的包装器。如果你可以用apply(不带l)来表达它,事情可能真的会加速。
  • 为什么要将spliz 创建为折叠字符串并使用eval(parse())?如果您不需要 spliz 作为其他任何地方的字符串,您可以使用 spliz &lt;- c(TRUE, rep(FALSE, (row_id-1)))d$Tag &lt;- cumsum(rep(spliz,4))
  • 我有一个指南“通过将 For-Loop 重写为 Lapply 调用来并行化它”(jottr.org/2019/01/11/…),了解如何实现这一点 - 希望对您有所帮助。
  • @zx8754 我已经创建了一个虚拟数据......是的,我同意我采用了不同的方法来创建虚拟数据。但是我们的主要目标是`如何使 for 循环更快,而不是我们可以使用 lapply 吗?
  • @LAP 那段代码是用来创建分类变量的

标签: r for-loop optimization parallel-processing lapply


【解决方案1】:

不确定您的预期输出是什么,但应该可以这样:

v <- do.call(rbind, 
             lapply(split(d, d$Tag), function(s){
               res <- s
               res$R2 <- ifelse(as.character(res$y_pred) == "L3", 
                                cumsum(as.character(res$y_pred) == "L3")), 0)
               res$seq <- seq_along(1:nrow(res))
               re$Aoc <- (1-(res$R2/res$seq))*100
               res$Aoc1 <- (res$R2/res$seq)
               #return
               res
             }))

【讨论】:

  • 对于 ifelse 语句,我们必须添加 temp &lt;- temp + 1 。我们怎么能做到这一点。如果 ifelse 语句为 True,则 R2 中的值应按顺序不断变化,而不是仅将 1 分配给 R2
  • v1 &lt;- do.call(rbind, lapply(split(d, d$Tag), function(s){ s$y_pred &lt;- as.character(s$y_pred) temp = 0 res &lt;- s res$R2 &lt;- ifelse(as.character(res$y_pred) == "L3", temp &lt;- temp + 1, 0) #res$R2 &lt;- ifelse(s$y_pred == "L3", temp &lt;- temp + 1, 0) res$seq &lt;- seq_along(1:nrow(res)) res$Aoc &lt;- (1-(res$R2/res$seq))*100 res$Aoc1 &lt;- (res$R2/res$seq) res }))
  • 我尝试将temp = 0 放入函数中,但这并不是在ifelse 语句中添加temp &lt;- temp + 1
  • @Harvey 可能将 ifelse 更改为 cumsum:res$R2 &lt;- cumsum(as.character(res$y_pred) == "L3"))
  • 它起作用了,但是假设我想对某些事件进行计数。在那我们应该如何分配一个变量,因为我尝试分配 temp = 0 并做了 temp
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2019-12-01
  • 1970-01-01
  • 2015-08-20
  • 2021-08-09
  • 2011-10-31
相关资源
最近更新 更多