【问题标题】:Replace rbind in for-loop with lapply? (2nd circle of hell)用lapply替换for循环中的rbind? (地狱第二圈)
【发布时间】:2015-01-06 18:14:59
【问题描述】:

我在优化一段 R 代码时遇到问题。以下示例代码应该说明我的优化问题:

一些初始化和函数定义:

a <- c(10,20,30,40,50,60,70,80)
b <- c(“a”,”b”,”c”,”d”,”z”,”g”,”h”,”r”)
c <- c(1,2,3,4,5,6,7,8)
myframe <- data.frame(a,b,c)
values <- vector(length=columns)
solution <- matrix(nrow=nrow(myframe),ncol=columns+3)

myfunction <- function(frame,columns){
athing = 0
   if(columns == 5){
   athing = 100
   }
   else{
   athing = 1000
   }
value[colums+1] = athing
return(value)}

有问题的 for 循环如下所示:

columns = 6
for(i in 1:nrow(myframe){
   values <- myfunction(as.matrix(myframe[i,]), columns)
   values[columns+2] = i
   values[columns+3] = myframe[i,3]
   #more columns added with simple operations (i.e. sum)

   solution <- rbind(solution,values)
   #solution is a large matrix from outside the for-loop
}

问题似乎出在rbind 函数上。 我经常收到关于solution 大小的错误消息,一段时间后它似乎太大了(超过50 MB)。 我想用列表和lapply 和/或foreach 替换这个循环和rbind。我已经开始将 myframe 转换为列表。

myframe_list <- lapply(seq_len(nrow(myframe)), function(i) myframe[i,])

虽然我尝试应用此very good introduction to parallel processing,但我并没有真正走得更远。

如何在不更改 myfunction 的情况下重建 for 循环?显然我对不同的解决方案持开放态度......

编辑:这个问题似乎直接来自2nd circle of hell from the R Inferno。有什么建议吗?

【问题讨论】:

  • 什么是columns?我是否理解得很好,value 是具有 2 个可能值的向量:100 和 1000?
  • 在for循环之前...columnsvalues-framesolutions-martrix的变化列数。取决于特定的输入(在实际脚本中可能有 10000+ 列)。 myfunction 在实际脚本中要复杂得多。它仍然只是一系列 if 分支。每个values-frame 由for 循环和myfunction 构建,并绑定到solutions 矩阵。
  • 你试试solution &lt;- rbind(solution,values)试试solution[i,] = values?据我了解,您已经创建了solution 矩阵,因此无需绑定下一行。将现有行 od NA 更改为 value 更有效。也许这样就可以了?
  • solution 已创建但“未完成”,因为此处显示的 for 循环位于另一个依赖于 solution 的 for 循环中。

标签: r for-loop optimization lapply rbind


【解决方案1】:

在这样的循环中使用rbind 是不好的做法的原因是,在每次迭代中,您都会放大您的solution 数据框,然后将其复制到一个新对象,这是一个非常缓慢的过程,也可以导致记忆问题。解决此问题的一种方法是创建一个列表,其第 i 个组件将存储第 i 个循环迭代的输出。最后一步是在该列表上调用 rbind(最后只调用一次)。这看起来像

my.list <- vector("list", nrow(myframe))
for(i in 1:nrow(myframe)){
    # Call all necessary commands to create values
    my.list[[i]] <- values
}
solution <- rbind(solution, do.call(rbind, my.list))

【讨论】:

  • 这正是我想要的!非常感谢。它将我的机器上的执行时间从 40 分钟减少到 2 分钟,并尽可能减少了columns。顺便说一句:我尝试的最后一件事是solution &lt;- do.call('rbind',my.list)。这显然是行不通的。再次感谢!
  • 对于解决方案部分,您可以使用它。 do.call(Map, c(rbind, my.list))
【解决方案2】:

有点想发表评论,所以我把它放在这里: 如果事先知道columns

    myfunction <- function(frame){
    athing = 0
       if(columns == 5){
       athing = 100
       }
       else{
       athing = 1000
       }
    value[colums+1] = athing
    return(value)}

    apply(myframe, 2, myfunction)

如果columns不是通过环境给出的,你可以使用:

apply(myframe, 2, myfunction, columns) 与您原来的 myfunction 定义。

【讨论】:

  • 对不起,但我不明白这将如何导致相同的结果。 ;) 在这种情况下,我的solution-matrix会在哪里?从原始 for 循环中添加的列在哪里?
猜你喜欢
  • 2020-06-03
  • 2021-08-09
  • 1970-01-01
  • 1970-01-01
  • 2011-04-10
  • 2013-12-12
  • 2021-11-14
  • 2021-07-31
  • 2019-04-04
相关资源
最近更新 更多