【问题标题】:How to improve speed for table with millions of rows如何提高数百万行表的速度
【发布时间】:2019-04-11 18:07:07
【问题描述】:

我是 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,那么它会将 0.1 添加到 ID 并保留在“新”列中。这是输出:

   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 万行,感觉它永远不会这样做 - 我试着等待几个小时没有成功。

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

【问题讨论】:

  • 你能说得更具体点吗?比如你想达到什么条件?
  • @sai saran 抱歉,我不确定我是否理解您的问题,但我想弄清楚为什么上述代码在大型数据集上使用时会花费很长时间,以及如何改进。

标签: r dplyr data.table tidyverse


【解决方案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 

【讨论】:

    猜你喜欢
    • 2019-07-31
    • 1970-01-01
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    • 2017-10-01
    • 2021-11-07
    • 2023-03-06
    • 1970-01-01
    相关资源
    最近更新 更多