2013-10-17 34 views
2

我正在處理從金融中心刪除郵件的財務問題。我使用的是data.table,我對它的性能和易於處理非常滿意。高效地匹配多個變量的行 - 排除列

雖然我總是問自己如何改進和使用data.table的全部功能。

這是我的任務的示例:

set.seed(1) 
DT <- data.table(SYM = c(rep("A", 10), rep("B", 12)), PRC = format(rlnorm(22, 2), digits = 2), VOL = rpois(22, 312), ID = c(seq(1000, 1009), seq(1004, 1015)), FLAG = c(rep("", 8), "R", "A", rep("", 4), "R", rep("", 7))) 
DT$PRC[9] <- DT$PRC[6] 
DT$PRC[7] <- DT$PRC[6] 
DT$VOL[9] <- DT$VOL[6] 
DT$VOL[7] <- DT$VOL[6] 
DT$PRC[15] <- DT$PRC[13] 
DT$VOL[15] <- DT$VOL[13] 
## See the original dataset 
DT 
## Set the key 
setkey(DT, "SYM", "PRC", "VOL", "FLAG") 
## Get all rows, that match a row with FLAG == "R" on the given variables in the list 
DT[DT[FLAG == "R"][,list(SYM, PRC, VOL)]] 
## Remove these rows from the dataset 
DT <- DT[!DT[FLAG == "R"][,list(SYM, PRC, VOL)]] 
## See the modified data.table 
DT 

我的問題是現在:

  1. 這是執行我的任務的有效方式或確實存在着更多的東西「data.table」樣式?密鑰設置是否有效?
  2. 如果我不僅要有三個變量匹配(這裏是:SYM,PRC,VOL),而且還有更多,是否存在排除項目(我知道我可以使用它的數據),我該如何執行我的任務。框架樣式,但我想知道是否有一個更優雅的方式data.table)?
  3. 什麼是在最後一個命令中複製?繼remove row by reference之後,我認爲複製是唯一的方法。如果我有幾項任務,我可以以某種方式複合它們並避免爲每項任務進行復制?
+0

+1是數據隨機的?我看到一個'rlnorm'(儘管我不確定那是什麼)。你可以在頂部使用'set.seed(1)'(或其他種子),所以我們都在同一頁面上?儘管我會保留表DT1 < - DT [!...]的兩個版本,因爲我不習慣記住內存約束,所以我會盡我所能。 – Frank

+0

@Frank感謝您的評論!你是對的!而且我的數據不是隨機的:) –

回答

1

如果您只是設置鍵執行此操作,@ eddi的答案是最好的,最容易閱讀。

setkey(DT, SYM, PRC, VOL) 
#^as in @eddi's answer, since you are not using the rest of the key 
microbenchmark(
    notjoin=DT[!DT[FLAG == "R"][,list(SYM, PRC, VOL)]], 
    logi_not=DT[!DT[,rep(any(FLAG=='R'),.N),by='SYM,PRC,VOL']$V1], 
    idx_not=DT[!DT[,if(any(FLAG=='R')){.I}else{NULL},by='SYM,PRC,VOL']$V1], 
    SD=DT[,if(!any(FLAG=='R')){.SD}else{NULL},by='SYM,PRC,VOL'], 
    eddi=DT[!DT[FLAG == "R"]], 
    times=1000L 
) 

結果:

Unit: milliseconds 
    expr  min  lq median  uq  max neval 
    notjoin 4.983404 5.577309 5.715527 5.903417 66.468771 1000 
logi_not 4.393278 4.960187 5.097595 5.273607 66.429358 1000 
    idx_not 4.523397 5.139439 5.287645 5.453129 15.068991 1000 
     SD 3.670874 4.180012 4.308781 4.463737 9.429053 1000 
    eddi 2.767599 3.047273 3.137979 3.255680 11.970966 1000 

。另一方面,有幾個選項上面不要求你的操作涉及的關鍵分組。假設你要麼...

  • 正在做這一次使用組以外的鍵(你不想改變)或
  • 想要做副本之前執行這樣使用不同的分組幾個操作操作刪除行,newDT <- DT[...](如OP的第3點所述)。

setkey(DT,NULL) 
shuffDT <- DT[sample(1:nrow(DT))] # not realistic, of course 
# same benchmark with shuffDT, but without methods that require a key 
# Unit: milliseconds 
#  expr  min  lq median  uq  max neval 
# logi_not 4.466166 5.120273 5.298174 5.562732 64.30966 1000 
# idx_not 4.623821 5.319501 5.517378 5.799484 15.57165 1000 
#  SD 4.053672 4.448080 4.612213 4.849505 66.76140 1000 

在這些情況下,OP和eddi的方法不可用(因爲加入需要密鑰)。對於一次性操作,使用.SD似乎更快。對於按多個條件進行子集劃分,您需要在製作副本newDT <- DT[!union(badrows1,badrows2,...)]之前跟蹤要保留/放下的行。

DT[,rn:=1:.N] # same as .I 
badflagrows <- DT[,if(any(FLAG=='R')){rn}else{NULL},by='SYM,PRC,VOL']$V1 
# fill in next_cond, next_grp 
badnextrows <- DT[!badflagrows][, 
    if(any(next_cond)){rn}else{NULL},by='next_grp']$V1 

也許類似的東西可以用邏輯子集(在基準「logi_not」),這是一個快一點完成。

1

我很困惑,爲什麼你的項設置爲FLAG,是不是你想要的只是

setkey(DT, SYM, PRC, VOL) 

DT[!DT[FLAG == "R"]] 
+0

是的,速度要快得多。 – Frank

+0

@eddi確實如此。我很高興知道,表格必須在其關鍵字中包含「FLAG」,才能在此變量中搜索「R」。非常感謝您的幫助! –