快速处理大型表和表列 - 应用太慢

时间:2014-09-01 13:57:12

标签: r performance apply

我已经使用R很长一段时间了,我有一个特定的小任务的工作代码。但我想知道是否有更快的解决方案。

问题很简单:我的数据框tbl有两列IDNrBlocks。 ID不是唯一的,可能会多次出现,但具有相同或不同的NrBlocks。该表实际上有更多列,但这些细节在这里无关紧要。我想要的只是每个唯一NrBlocks的{​​{1}}值的总和。

工作代码(在重命名之前,我希望我没有因为这里的简化而引入拼写错误):

ID

有关提高速度的建议吗?

2 个答案:

答案 0 :(得分:1)

强制性data.table解决方案 -

options(stringsAsFactors=FALSE)
library(data.table)
##
set.seed(1234)
dTbl <- data.table(
  ID = sample(c(letters,LETTERS),100000,replace=TRUE),
  NrBlocks = rnorm(100000),
  key = "ID")
##
gTbl <- dTbl[
  ,
  list(sumNrBlocks = sum(NrBlocks)),
  by = list(ID)]
##
> head(gTbl)
   ID sumNrBlocks
1:  A    56.50234
2:  B   -13.61380
3:  C    24.66750
4:  D    65.18829
5:  E    26.14085
6:  F    41.64376

时间:

library(microbenchmark)
##
uniqueIDs <- unique(dTbl$ID)
f1 <- function(){
  sapply(1:length(uniqueIDs),
         FUN = function(x){
           sum(dTbl[which(dTbl$ID == uniqueIDs[x]),]$NrBlocks)
         }
  )
}
##
f2 <- function(){
  dTbl[
    ,
    list(sumNrBlocks = sum(NrBlocks)),
    by = list(ID)]
}
##
Res <- microbenchmark(
  f1(),
  f2(),
  times=100L)
Res
> Res
Unit: milliseconds
 expr        min         lq     median         uq        max neval
 f1() 139.054620 141.534227 144.213253 156.747569 193.278071   100
 f2()   1.813652   1.911069   1.980874   2.140971   3.522545   100

多列:

dTbl2 <- copy(dTbl)
set.seed(1234)
dTbl2[,col3:=rexp(100000)]
dTbl2[,col4:=col3*2]
##
gTbl2 <- dTbl2[
  ,
  lapply(.SD,sum),
  by=list(ID)]
##
> head(gTbl2)
   ID  NrBlocks     col3     col4
1:  A  56.50234 1933.443 3866.886
2:  B -13.61380 1904.282 3808.563
3:  C  24.66750 1834.655 3669.310
4:  D  65.18829 1884.364 3768.728
5:  E  26.14085 1874.761 3749.523
6:  F  41.64376 1977.219 3954.438

具有规范的多列

gTbl2.2 <- dTbl2[
  ,
  lapply(.SD,sum),
  by=list(ID),
  .SDcols=c(2,4)]
##
> head(gTbl2.2)
   ID  NrBlocks     col4
1:  A  56.50234 3866.886
2:  B -13.61380 3808.563
3:  C  24.66750 3669.310
4:  D  65.18829 3768.728
5:  E  26.14085 3749.523
6:  F  41.64376 3954.438

答案 1 :(得分:0)

如果您有500毫秒的空余时间,可以在一个简单的行中使用aggregate执行此操作。

aggregate(NrBlocks ~ ID, dat, mean)
microbenchmark(aggregate(NrBlocks ~ ID, dat, mean))
# Unit: milliseconds
#  expr     min       lq   median       uq      max neval
#   f() 655.218 655.6562 656.6428 661.6947 667.0888   100

其中dat是从nrussell表创建的数据框。

dim(dat)
# [1] 10000 2