当涉及多个任务和/或if语句时,避免for循环

时间:2016-11-30 19:22:29

标签: r for-loop

我有一个包含数千行的大型data.frame,我每次循环时都会从第1行创建一个子集,每次迭代增加一行。

在每个子集上,我执行了几个任务,这些任务来自对编程的pythonic理解,我执行'for'循环。例如。

df <- data.frame(a=c(1:10), b=c(11:20), c=c(21:30), d=c(31:40))
for (index in 1:nrow(df)) {
  thisSubset <- df[1: index,] 

  #loop 1  
  new1 <- ncumeric(nrow(thisSubset))
  for (i in 1:nrow(thisSubset)) {              
         var1 = 5 - thisSubset$b[i]        
         new1[i] <- 1/exp(var1*log(2));
  }
  #loop 2         
  new2 <- numeric()
  for (i in 1:nrow(thisSubset)) if (thisSubset$c[i] >25) {
    new2<- c(new2, (thisSubset$a[i]/exp(5*log(2))))
  } 
  #loop 3  
  new3 <- numeric(nrow(thisSubset)) 
  for (i in 1:nrow(thisSubset)) if (thisSubset$a[i] < 5) {
      new3[i] <- thisSubset$d[i]-thisSubset$d[i+1]/2
  } else {
    new3[i] <- thisSubset$d[i]-thisSubset$d[i-1]/2 
    }
  #loop x
  #... 
}

随着我的数据集变大,处理时间呈指数级增长到几个小时。我很欣赏在R中有更好的工作方式来执行类似的任务(例如应用),但是当每个循环中发生了几件事情以及每行使用多个元素时,我还能使用除“for”以外的任何东西吗?如果有人能给我一个上面提到的每个或任何循环的例子,我将不胜感激。

2 个答案:

答案 0 :(得分:1)

For循环并不比它们的表兄弟更慢(事实上,有时它们甚至可以更快!)。真正的速度增益来自于尽可能将显式for循环转换为矢量化代码。例如,代码中的循环1和循环2可以转换为矢量化语句,如下所示:

#loop 1 
new1 <- 1 / exp((5 - thisSubset$b) * log(2))

#loop 2         
new2 <- thisSubset$a[thisSubset$c > 25] / exp(5 * log(2))

当你的计算取决于向量的索引(例如在循环3中)时,事物变得有点棘手,但是确实存在具有各种&#34;滚动&#34;的有效实现的包。函数(有关详细信息,请参阅rollzoo包。)

如果您确实需要使用for循环,请记住,您应该始终预先分配您的&#34;结果&#34;在开始迭代之前的向量而不是在迭代期间增长它:

#bad
new2 <- numeric()
for (i in 1:nrow(thisSubset)) {
  if (thisSubset$c[i] >25) {
    new2<- c(new2, (thisSubset$a[i]/exp(5*log(2))))
  }
} 

#good
new2 <- numeric(length = nrow(thisSubset))
for (i in 1:nrow(thisSubset)) {
  if (thisSubset$c[i] >25) {
    new2[i] <- (thisSubset$a[i]/exp(5*log(2)))
  }
} 

这可以防止R在每次迭代后复制new2,从而产生更快的代码。

答案 1 :(得分:0)

R是一种矢量化语言,因此大多数函数可以在单个语句中应用于整个列,而不会向下迭代每一行。例如,我向你的三个内部循环进行了矢量化:

df <- data.frame(a=c(1:10), b=c(11:20), c=c(21:30), d=c(31:40))

 thisSubset <- df

  #loop 1  
  new1 <- numeric(nrow(thisSubset))
    var1 = 5 - thisSubset$b       
    new1 <- 1/exp(var1*log(2));

  #loop 2         
  new2 <- numeric()
  new2<-  (thisSubset$a[thisSubset$c >25]/exp(5*log(2)))

  #loop 3  
  new3 <- numeric(nrow(thisSubset)) 
  dplus1 <-c(thisSubset$d[-1], thisSubset$d[length(thisSubset$d)])
  dminus1 <-c(thisSubset$d[1], thisSubset$d[-length(thisSubset$d)])
  new3<- ifelse((thisSubset$a < 5), thisSubset$d-dplus1/2, thisSubset$d-dminus1/2)
  #loop x
  #... 

你的外环是不必要的 有关其他评论,请参阅Mark的解决方案。