比较记录结果和双循环

时间:2012-03-05 21:00:26

标签: performance r for-loop sum apply

我有一个双循环,我不仅不喜欢,而且需要14天才能在我的计算机上运行,​​因为它会超过3200条记录和1090个变量,每次迭代大约.12。

较小的可重现位。它只是检查两个记录之间相同列中的数量,不包括NA。然后它将结果附加到原始数据框。

y <- data.frame(c(1,2,1,NA,NA),c(3,3,3,4,NA),c(5,4,5,7,7),c(7,8,7,9,10))
resultdf <- NULL
for(i in 1:nrow(y))
{
  results <- NULL
  for(j in 1:nrow(y))
  {
    results <- c(results,sum((y[i,]==y[j,]),na.rm=TRUE))
  }
  resultdf <- cbind(resultdf,results)
}
y <- cbind(y,resultdf)

我有重复的计算,可以避免大约7天。

如果我理解正确,一些应用函数在C中可能更快。虽然我无法上班。如果有一个运行速度更快的包,我也很好奇。任何人都可以帮助加快计算速度吗?

谢谢!

4 个答案:

答案 0 :(得分:3)

这是另一种解决方案,使用outer

f <- function(i,j) sum(y[i,] == y[j,], na.rm=TRUE)
d <- outer( 1:nrow(y), 1:nrow(y), Vectorize(f) )

答案 1 :(得分:3)

我已根据您的规格创建数据,并使用@BenBolker关于使用矩阵的建议:

> y <- matrix(sample(c(1:9, NA), 3200 * 1090, replace = TRUE),
+             nrow = 3200, ncol = 1090)

并比较了三种不同实现的计算时间:

@Andrei建议

f1

> f1 <- function(y)apply(y, 1, function(r1)
+                  apply(y, 1, function(r2)sum(r1==r2, na.rm=TRUE)))

> system.time(r1 <- f1(y))
   user  system elapsed 
 523.51    0.77  528.73 
@VincentZoonekynd建议

f2

> f2 <- function(y) {
+   f <- function(i,j) sum(y[i,] == y[j,], na.rm=TRUE)
+   d <- outer( 1:nrow(y), 1:nrow(y), Vectorize(f) )
+   return(d)
+ }
> system.time(r2 <- f2(y))
   user  system elapsed 
 658.94    1.96  710.67

f3是@BenBolker建议的上三角形的双循环。它也比你的OP更有效率,因为它预先分配了输出矩阵:

> f3 <- function(y) {
+   result <- matrix(NA, nrow(y), nrow(y))
+   for (i in 1:nrow(y)) {
+     row1 <- y[i, ]
+     for (j in i:nrow(y)) {
+       row2 <- y[j, ]
+       num.matches  <- sum(row1 == row2, na.rm = TRUE)
+       result[i, j] <- num.matches
+       result[j, i] <- num.matches
+     }
+   }
+   return(result)
+ }

> system.time(r3 <- f3(y))
   user  system elapsed 
 167.66    0.08  168.72 

所以双循环是所有三个循环中最快的,尽管不像其他两个答案那样优雅和紧凑。

答案 2 :(得分:2)

确实,你可以使用apply函数。鉴于早期暗示矩阵运行得更快,我会尝试:

ym <- as.matrix(y)
resultdf <- apply(ym, 1, function(r1) apply(ym, 1, function(r2) sum(r1==r2, na.rm=TRUE)))

答案 3 :(得分:1)

你可以摆脱内循环(使用来自@ flodel的答案的yf3):

ty <- t(y)
ix <- rep(1:nrow(y),each = ncol(y))
f4 <- function(y){
    result <- matrix(0L, nrow(y), nrow(y))
    for(r in 1:nrow(y))
        result[r,] <- rowsum(as.numeric(ty == y[r,]), ix, na.rm = T)
    result
}



> system.time(out <- f4(y))
   user  system elapsed 
 52.616  21.061  74.000 
> system.time(out <- f3(y))
   user  system elapsed 
244.751   0.136 244.954 
> 

它实际上做了两次相同的计算,但仍然快了5倍。通过使用rowsum的内部工作,你可以使它再快4倍。有关示例,请参阅此question