如何在R中加快顺序分析的速度?

时间:2019-05-17 15:19:29

标签: r performance loops

在使用之前的操作子结果时,我需要随后分析数据集。

据R所知,我决定使用此方法,而我尝试的解决方案之一是使用for循环。

我遍历的数据集大约有800万行,其中有4列。

我使用一个data.table并且变量是字符类型,例如“ XXXXXXXXX”

我试图遍历,但是每个周期大约需要0.7秒,而“ <-”操作需要半秒。

任何人都可以推荐更好的技术。可能是rcpp,应用还是其他?

感谢您的支持,

霍尔格

'%!in%' <- function(x,y)!('%in%'(x,y))
library('data.table')    


dt_loop <- data.table(
              paste0("XXXXXXXXXX", 1:80000000),
              paste0("YXXXXXXXXX", 1:80000000),
              paste0("ZXXXXXXXXX", 1:80000000),
              paste0("AXXXXXXXXX", 1:80000000)
      )

    colnames(dt_loop)[colnames(dt_loop)=="V1"] <- "m"
    colnames(dt_loop)[colnames(dt_loop)=="V2"] <- "c"
    colnames(dt_loop)[colnames(dt_loop)=="V3"] <- "ma"
    colnames(dt_loop)[colnames(dt_loop)=="V4"] <- "unused"


    for(i in 1:nrow(dt_loop)){
      m <- dt_loop$m[i]
      c <- dt_loop$m[i]

      if(m %!in% dt_loop$ma[1:i] & c %!in% dt_loop$ma[1:i]){
        dt_loop$ma[i] <- m
      } else { 
        if(m %in% dt_loop$ma[1:i]){
          dt_loop$ma[i] <- m
        } else {
          dt_loop$ma[i] <- c
        }
      } 
    }

1 个答案:

答案 0 :(得分:0)

这是自联接笛卡尔积的解决方案。我修改了您的代码以获得有意义的结果。我还认为,如果您有800万行,那么当第n个循环依赖于第n个循环时,您将遇到性能问题。

数据结构的变化:

  1. 使用sample在数据表中获得一些重复
  2. 将列名简化为data.table函数setnames()
  3. 添加了ID字段
  4. 删除了未使用的列。
'%!in%' <- function(x,y)!('%in%'(x,y))
library('data.table')    

# Generate Data -----------------------------------------------------------

set.seed(1)
n_rows <- 10
dt_loop <- data.table(
  sample(paste0("X", 1:n_rows), n_rows, replace = T),
  sample(paste0("Y", 1:n_rows), n_rows, replace = T),
  sample(paste0("X", 1:n_rows), n_rows, replace = T)
)

setnames(dt_loop, c('m', 'c', 'ma'))
dt_loop[, ID := .I]

我对您的循环进行了重大更改。

  1. 分配了c <- dt_loop$c[i],因为我不知道在那里使用了m。
  2. 由于新分配了if,因此删除了第一条c语句。
# Original loop with Minor Mod --------------------------------------------

for(i in 1:nrow(dt_loop)){
  m <- dt_loop$m[i]
  c <- dt_loop$c[i] #changed to c instead of m

#Removed first ifelse condition
  #as it didn't make sense as originally constructed

  # if(m %!in% dt_loop$ma[1:i] & c %!in% dt_loop$ma[1:i]){
    # dt_loop$ma2[i] <- m
  # } else {
    if(m %in% dt_loop$ma[1:i]){
      dt_loop$ma2[i] <- m
    } else {
      dt_loop$ma2[i] <- c
    }
  # }
}
dt_loop

      m   c  ma ID ma2
 1:  X3  Y3 X10  1  Y3
 2:  X4  Y2  X3  2  Y2
 3:  X6  Y7  X7  3  Y7
 4: X10  Y4  X2  4 X10
 5:  X3  Y8  X3  5  X3
 6:  X9  Y5  X4  6  Y5
 7: X10  Y8  X1  7 X10
 8:  X7 Y10  X4  8  X7
 9:  X7  Y4  X9  9  X7
10:  X1  Y8  X4 10  X1

当我将行增加到10,000时,自联接似乎比循环快,但是它仍然变慢。值得注意的是,您可以看到ma上有重复项,因为笛卡尔乘积扩展了结果,所以您得到了N == 2

我相信,有一些方法可以使自连接起作用,这样您只能得到第N行,这应该可以减轻一些压力。

dt_loop[dt_loop
        , on = .(ID <= ID
                 , ma = m)
        , .(.N
            ,i.ma2 #for comparison - remove
            ,ma3 = ifelse(is.na(x.ID), i.c, i.m)
            ,i.ID, i.m, i.c, i.ma
            ,x.ID, x.m, x.c, x.ma 
        )
        , by = .EACHI
        , allow.cartesian = T]

    ID  ma N i.ma2 ma3 i.ID i.m i.c i.ma x.ID  x.m  x.c x.ma
 1:  1  X3 0    Y3  Y3    1  X3  Y3  X10   NA <NA> <NA> <NA>
 2:  2  X4 0    Y2  Y2    2  X4  Y2   X3   NA <NA> <NA> <NA>
 3:  3  X6 0    Y7  Y7    3  X6  Y7   X7   NA <NA> <NA> <NA>
 4:  4 X10 1   X10 X10    4 X10  Y4   X2    1   X3   Y3  X10
 5:  5  X3 2    X3  X3    5  X3  Y8   X3    2   X4   Y2   X3
 6:  5  X3 2    X3  X3    5  X3  Y8   X3    5   X3   Y8   X3
 7:  6  X9 0    Y5  Y5    6  X9  Y5   X4   NA <NA> <NA> <NA>
 8:  7 X10 1   X10 X10    7 X10  Y8   X1    1   X3   Y3  X10
 9:  8  X7 1    X7  X7    8  X7 Y10   X4    3   X6   Y7   X7
10:  9  X7 1    X7  X7    9  X7  Y4   X9    3   X6   Y7   X7
11: 10  X1 1    X1  X1   10  X1  Y8   X4    7  X10   Y8   X1