2017-04-10 55 views
1

我必須經常子集一個data.frame的序列(每次運行數百萬次)。 data.frame s近似爲200行×30列。根據狀態,data.frame中的值會從一次迭代更改爲下一次迭代。因此,在開始時做一個子集是行不通的。有沒有辦法加快子集的較小的數據。框架

與此相反的問題,when a data.table starts to be faster than a data.frame,我找子集的速度,彌補了data.frame/data.table

以下最低可重複的例子顯示了一個給定的大小,即data.frame似乎是最快的:

library(data.table) 
nmax <- 1e2 # for 1e7 the results look as expected: data.table is really fast! 
set.seed(1) 
x<-runif(nmax,min=0,max=10) 
y<-runif(nmax,min=0,max=10) 
DF<-data.frame(x,y) 
DT<-data.table(x,y) 

summary(microbenchmark::microbenchmark(
    setkey(DT,x,y), 
    times = 10L, unit = "us")) 

#    expr min  lq mean median  uq  max neval 
# 1 setkey(DT, x, y) 70.326 72.606 105.032 80.3985 126.586 212.877 10 

summary(microbenchmark::microbenchmark(
    DF[DF$x>5, ], 
    `[.data.frame`(DT,DT$x < 5,), 
    DT[x>5], 
    times = 100L, unit = "us")) 
#        expr  min  lq  mean median  uq  max neval 
# 1     DF[DF$x > 5, ] 41.815 45.426 52.40197 49.9885 57.4010 82.110 100 
# 2 `[.data.frame`(DT, DT$x < 5,) 43.716 47.707 58.06979 53.5995 61.2020 147.873 100 
# 3      DT[x > 5] 205.273 214.777 233.09221 222.0000 231.6935 900.164 100 

有什麼我可以做的,以提高性能?輸入後

編輯:

  • 我運行離散事件仿真和每個事件我有一個列表來搜索(我不介意它是否是一個data.framedata.table)。最有可能的是,我可以實施一種不同的方法,但是我必須重新編寫超過3年開發的代碼。目前,這不是一個選項。但如果沒有辦法讓速度更快,這將成爲未來的選擇。
  • 從技術上講,它不是一個data.frames的序列,而是一個data.frame,它隨着每次迭代而變化。但是,這對「如何更快地獲得子集」沒有影響,我希望現在的問題更全面。
+0

除非您正在對數據進行幾乎隨機選擇,否則您可能想要創建一個您可以參考的現有子集列表,而不是以反覆的方式重複使用相同的數據框? –

+1

data.table子集中涉及開銷。另請參閱http://stackoverflow.com/a/20179189/1412059 – Roland

+4

您應該詢問有關您的實際問題的正確問題。如果你將數據框架子集數百萬次,那麼你的方法是錯誤的。 – Roland

回答

1

您將看到轉換爲矩陣的性能提升。如果您的data.frame的全部內容是數字(或者可以在沒有太多麻煩的情況下進行轉換),那麼這是一個可行的選擇。

我們走吧。首先,我修改了數據大小爲200x30有它:

library(data.table) 
nmax = 200 
cmax = 30 
set.seed(1) 
x<-runif(nmax,min=0,max=10) 
DF = data.frame(x) 
for (i in 2:cmax) { 
    DF = cbind(DF, runif(nmax,min=0,max=10)) 
    colnames(DF)[ncol(DF)] = paste0('x',i) 
} 
DT = data.table(DF) 
DM = as.matrix(DF) # # # or data.matrix(DF) if you have factors 

和比較,排名從最快到最慢:

summary(microbenchmark::microbenchmark(
    DM[DM[, 'x']>5, ], # # # # Quickest 
    as.matrix(DF)[DF$x>5, ], # # # # Still quicker with conversion 
    DF[DF$x>5, ], 
    `[.data.frame`(DT,DT$x < 5,), 
    DT[x>5], 
    times = 100L, unit = "us")) 

#        expr  min  lq  mean median  uq  max neval 
# 1   DM[DM[, "x"] > 5, ] 13.883 19.8700 22.65164 22.4600 24.9100 41.107 100 
# 2  as.matrix(DF)[DF$x > 5, ] 141.100 181.9140 196.02329 195.7040 210.2795 304.989 100 
# 3     DF[DF$x > 5, ] 198.846 238.8085 260.07793 255.6265 278.4080 377.982 100 
# 4 `[.data.frame`(DT, DT$x < 5,) 212.342 268.2945 346.87836 289.5885 304.2525 5894.712 100 
# 5      DT[x > 5] 322.695 396.3675 465.19192 428.6370 457.9100 4186.487 100 

如果用例涉及查詢多次的數據,那麼你只能進行一次轉換,並將速度提高一個數量級。

+0

酷,我已經放棄了,但似乎總有人有一個好主意:-) – Christoph

相關問題