关于在R中加速我的5个循环的建议?

时间:2016-12-13 14:14:01

标签: r performance loops

我有5个表,我想找到一些满足一些要求的组合。通过使用矩阵乘法创建所有可能的组合,然后选择满足我需求的行,我可以轻松地解决下面的数据。问题是我的原始问题包括5个表,每个表有200行。如果生成所有可能的组合,则需要几百gb的ram。

所以我尝试了这个:

x1 <- seq(1,10,1)
x2 <- seq(5,15,3)
x3 <- seq(2,11,1)
x4 <- seq(1,5,1)
x5 <- seq(1,20,2)

哪个应该满足:x1&lt; x2和x1 < X3。

nm <- data.frame(matrix(NA,1,5))

for(a in 1:length(x1)){
for(s in 1:length(x2)){
for(d in 1:length(x3)){
for(f in 1:length(x4)){
for(g in 1:length(x5)){

l1 <- x1[a]
l2 <- x2[s]

if(l1 < l2){

l3 <- x3[d]

if(l1 < l3){

l4 <- x4[f]
l5 <- x5[g]

fy <- c()
fy[1] <- l1
fy[2] <- l2
fy[3] <- l3
fy[4] <- l4
fy[5] <- l5

nm <- rbind(nm, fy)
}}}}}}}

在我原来的问题中,我有更多if语句,我希望这会提高速度。但我现在已经运行了大约24小时,但仍未完成。上面的问题花了我大约10s,这让我觉得它卡住了。

1 个答案:

答案 0 :(得分:2)

两个问题:

巨大的问题是你在循环中生长一个对象。这是最慢的操作,因为涉及巨大的操作系统开销。您需要预先分配对象,并且只在必要时将其增长为块。

中等问题是您使用data.frame来存储结果。 Data.frames很有用,但很慢。改为使用矩阵。

nm1 <- matrix(nrow = 1e3, ncol = 5) #adjust the chunk size to a reasonable estimate
rx <- 1

for(a in 1:length(x1)){
  for(s in 1:length(x2)){
    for(d in 1:length(x3)){
      for(f in 1:length(x4)){
        for(g in 1:length(x5)){

          l1 <- x1[a]
          l2 <- x2[s]

          if(l1 < l2){

            l3 <- x3[d]

            if(l1 < l3){

              l4 <- x4[f]
              l5 <- x5[g]

              if(rx > nrow(nm1)) nm1 <- rbind(nm1, matrix(nrow = 1e3, ncol = 5))

              nm1[rx, 1] <- l1
              nm1[rx, 2] <- l2
              nm1[rx, 3] <- l3
              nm1[rx, 4] <- l4
              nm1[rx, 5] <- l5

              rx <- rx + 1

            }}}}}}}

nm1 <- nm1[seq_len(rx - 1),]

时序:

Unit: milliseconds
       expr       min        lq      mean    median        uq       max neval cld
      mod()  589.2437  591.1576  594.4138  593.3678  595.0909  603.2087     5  a 
 original() 4934.4981 4952.4502 4980.6414 4953.3183 4985.7943 5077.1463     5   b

我们在没有真正开始考虑算法的情况下获得了10倍的性能提升。如果您有更多的data.frame增长迭代,这个因素会变得更大。如果这仍然太慢,您可以尝试使用编译器包对代码进行字节编译。使用Rcpp实现实际编译代码也是微不足道的。但是,您应该根据不断增加的迭代次数进行基准测试,并根据实际问题推断时间。您可能需要找到比蛮力更好的算法,或者考虑是否确实需要这样做。