2013-12-21 61 views
5

我想找到最快的方式來通過幾個數字列子集大型數據集。正如data.table所承諾的那樣,執行二進制搜索所花的時間比矢量掃描要快得多。然而,二進制搜索需要事先執行setkey。正如你在這段代碼中看到的那樣,它需要很長時間!一旦你把這個時間考慮在內,矢量掃描要快得多:data.table:矢量掃描v與數字列的二進制搜索 - 超慢setkey

set.seed(1) 
n=10^7 
nums <- round(runif(n,0,10000)) 
DT = data.table(s=sample(nums,n), exp=sample(nums,n), 
     init=sample(nums,n), contval=sample(nums,n)) 
this_s = DT[0.5*n,s] 
this_exp = DT[0.5*n,exp] 
this_init = DT[0.5*n,init] 
system.time(ans1<-DT[s==this_s&exp==this_exp&init==this_init,4,with=FALSE]) 
# user system elapsed 
# 0.65 0.01 0.67 
system.time(setkey(DT,s,exp,init)) 
# user system elapsed 
# 41.56 0.03 41.59 
system.time(ans2<-DT[J(this_s,this_exp,this_init),4,with=FALSE]) 
# user system elapsed 
# 0  0  0 
identical(ans1,ans2) 
# [1] TRUE 

我做錯了什麼?我已閱讀data.table常見問題解答等任何幫助將不勝感激。

非常感謝。

+0

設置一個關鍵字對data.table進行排序,並使用那些很昂貴的操作的唯一鍵值。如果你以後只做一次搜索,那麼這樣做不值得。然而,這個想法是,你設置一個鍵一次,然後重複觀察加速度。 – Roland

+2

問題的一部分是,您設置的方式是,您的關鍵字段是數字(雙精度浮點數),而不是整數。如果您設置了'num < - 1:10000'而不是'num < - round(runif(n,0,1000))',那麼索引速度快了8倍。不過,在這種情況下,仍然比沒有按鍵的矢量掃描慢一點。 – jlhoward

回答

5

行:

nums <- round(runif(n,0,10000)) 

nums類型numericinteger。這是一個很大的區別。 data.table常見問題和介紹適用於integercharacter列;你不會看到setkey在這些類型上很慢。例如:雖然

nums <- as.integer(round(runif(n,0,10000))) 
... 
setkey(DT,s,exp,init) # much faster now 

另外兩個點......

首先,排序/分揀操作在data.table v1.8.11當前開發版本快得多。 @jihoward是關於對數字列排序更爲耗時的操作。但是,1.8.11版本的速度仍然快了大約5-8倍(因爲執行6遍基數的命令,請檢查this post)。比較1.8.10和1.8.11之間的setkey操作所花費的時間:

# v 1.8.11 
system.time(setkey(DT,s,exp,init)) 
# user system elapsed 
# 8.358 0.375 8.844 

# v 1.8.10 
system.time(setkey(DT,s,exp,init)) 
# user system elapsed 
# 66.609 0.489 75.216 

這是我的系統上的8.5倍提高。所以,我的猜測是你的約需4.9秒。其次,正如@Roland所說的,如果你的目標是執行幾個子集,那就是你所要做的,那麼做一個設置鍵當然沒有意義,因爲它,必須找到列的順序,然後重新排列整個data.table(通過引用使內存佔用非常小,請在setkey上查詢this post以獲取更多信息)。