如何提高具有数百万行的表的速度

时间:2018-11-08 08:50:15

标签: r dplyr data.table tidyverse

我是R和Stack Overflow的新手,希望您能够解决我遇到的问题。我写了以下代码:

my = matrix(c(1,1,1,1,1,1,1,1,1,1,
          2,2,2,2,2,2,2,
          0,1,2,3,5,6,7,10,11,14,
          0,1,2,3,4,6,10),ncol = 2, nrow = 17)
colnames(my) = c("ID", "AGE")
my = as.data.frame(my)
my$new = my$ID
system.time(for (i in 1:length(my$ID)) {


ifelse(my$ID[i]==my$ID[i-1],
     ifelse(my$AGE[i]-my$AGE[i-1]==1, my$new[i]<-my$new[i-1],my$new[i]<-my$new[i-1]+0.1),
     my$new[i]<-my$ID[i])
})

它查看ID和AGE,如果AGE不等于以前的AGE + 1,则它将ID加0.1,并将其保留在“ new”列中。输出如下:

   ID AGE new
1   1   0 1.0
2   1   1 1.0
3   1   2 1.0
4   1   3 1.0
5   1   5 1.1
6   1   6 1.1
7   1   7 1.1
8   1  10 1.2
9   1  11 1.2
10  1  14 1.3
11  2   0 2.0
12  2   1 2.0
13  2   2 2.0
14  2   3 2.0
15  2   4 2.0
16  2   6 2.1
17  2  10 2.2

问题是,对于1000行的数据集,它确实非常快,但是当我在我的实际数据集上进行尝试时,该数据集的行数超过850万,感觉好像永远做不到-我尝试等待几个小时没有成功。

如果您提出提高速度/效率的方法,我将不胜感激。

1 个答案:

答案 0 :(得分:1)

处理大型数据集时,您需要尝试向量化计算以提高速度。

以下是使用dplyr包的示例(由于需要知道lag的先前值的功能AGE):

require(dplyr) # for group_by, mutate and %>%
require(microbenchmark) # to compare codes
# Your data
my           <- matrix(c(1,1,1,1,1,1,1,1,1,1,
                         2,2,2,2,2,2,2,
                         0,1,2,3,5,6,7,10,11,14,
                         0,1,2,3,4,6,10), ncol=2, nrow=17)
colnames(my) <- c("ID", "AGE")
my           <- as.data.frame(my)
my$new       <- my$ID
my2          <- my[rep(1:nrow(my), times=100),] # larger dataset

# Your function
f1 <- function(my) {
    for (i in 1:length(my$ID)) {
        ifelse(my$ID[i]==my$ID[i-1],
               ifelse(my$AGE[i]-my$AGE[i-1]==1, my$new[i] <- my$new[i-1],
                                                my$new[i] <- my$new[i-1]+0.1),
               my$new[i] <- my$ID[i])
    }
}

# dplyr function
f2 <- function(my) {
    my %>% group_by(ID) %>% # Work by ID
        mutate(new2=ifelse(is.na(lag(AGE)),  # If lag(AGE) is NA, it's the first record for the ID
                           FALSE,            # Thus, no increase of new3
                           AGE!=lag(AGE)+1), # new3=TRUE if AGE != 1+previous AGE
               new3=new+cumsum(new2)/10)     # increase the decimal if TRUE for the previous new2
}

对于较小的数据集,for循环更有效,但是对于较大的数据集,改进显而易见:

# Compare codes
microbenchmark(f1(my), f2(my),
               f1(my2), f2(my2))
Unit: milliseconds
    expr        min         lq       mean     median         uq       max neval cld
  f1(my)   1.470699   1.957855   2.750798   2.049954   2.243380  62.34942   100  a 
  f2(my)   2.741614   3.853356   4.235745   4.147085   4.421738  10.84871   100  a 
 f1(my2) 156.986927 215.515605 218.806729 222.390968 228.362988 290.19161   100   b
 f2(my2)   3.398812   4.377638   5.128953   4.659674   5.161190  28.97461   100  a