2014-09-01 83 views
1

我一直在使用R很長一段時間,而且我有一個特定的小任務的工作代碼。但我想知道是否有更快的解決方案。大表格和表格列的快速處理 - 應用太慢

問題很簡單:我有一個數據幀tbl,有兩列IDNrBlocks。 ID不是唯一的,可能會出現多次,但具有相同或不同的NrBlocks。這個表格實際上有更多的列,但這些細節在這裏是不相關的。我想要的是每個獨特的IDNrBlocks值的總和。

工作代碼(重命名前,我希望我沒有因簡化在這裏介紹錯別字):

uniqueIDs = unique(tbl$ID) #Precompute once 
sapply(1:length(uniqueIDs), 
     FUN = function(x){ 
     sum(tbl[which(tbl$ID == uniqueIDs[x]),]$NrBlocks) 
     } 
) 

的速度提升有什麼建議?

+0

聽起來像一個直接聚合。 '聚合(價值〜ID,數據,總和)' – 2014-09-01 14:07:13

+0

@RichardScriven,他要求一個快速解決方案:) – 2014-09-01 14:23:05

+0

非常感謝,正是我所期待的。爲什麼我從不會偶然發現聚合函數?你讓我今天一整天都感覺很好。似乎比我以前的解決方案更快,但也許有一個更快的變種? – 2014-09-01 14:24:16

回答

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 

中號與規範ultiple列 -

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 
+0

哇感謝不知道這件事,我會馬上測試它。感謝nrussell的幫助,非常感謝! – 2014-09-01 14:33:56

+0

沒問題 - 'data.table'是一個非常有用的軟件包。 – nrussell 2014-09-01 14:41:54

+0

哇,這是徹底的!像:)一樣。 – Arun 2014-09-07 20:42:42

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