2017-08-13 92 views
2

我想根據連接和固定值更新data.table中行的子集。data.table使用常量更新連接

d1 <- data.table(A = 5:1, B = letters[5:1])  
d2 <- data.table(C = letters[5:1], Z = 6:10) 
current.val <- 5 

我想要做的是更新d1基於與d2的連接,但只有在d1中的A = 5的地方。是這樣的:

d1[d2, D := i.Z ,on=.(B==C, A==current.val)] 

我目前的做法是增加一個新的列到D2,並將其設置爲固定值,並使用在連接:

d2[, current.val := 5] 
d1[d2, D := i.Z ,on=.(B==C, A==current.val)] 

這工作,但看起來像一個很多開銷。有一種更簡單的方法來在連接中使用常量值嗎?


(8/14)爲基準的新尺度範例:

d1 <- data.table(A = 100:1, B = 100000000:1, D = as.numeric(NA), key = c("A", "B")) 
d2 <- data.table(C = 100000000:1, Z = c(10:1)/10, key = "C") 
current.val <- 5 

system.time(d1[cbind(d2, A = current.val), on = .(B = C, A), D := i.Z]) 
system.time({setkey(d1, B, A); d1[d1[d2][A == current.val], D := Z]; setkey(d1, A, B)}) 
system.time(d1[d1[d2][A == current.val], D := Z]) # fastest, if inverse key order is acceptable 
+0

您的解決方案看起來很簡單。如果你不想創建一個列,那麼使用行索引,即'i1 < - d1 [,.I [A == current.val]]; d1 [i1,D:= d1 [i1] [d2,i.Z [i1],on =。(B == C)]]' – akrun

+0

不確定您是否在那裏做基準測試。我得到了「錯誤vecseq [...]加入結果超過2^31行」爲第二個。 – Frank

+0

Frank,請參閱下面@gcbenison的回答評論。病毒更新的帖子,以反映工作基準 – Ethan

回答

1

我目前的做法是增加一個新的列到D2,並將其設置爲固定值,並且使用在join [...]有沒有更簡單的方法在連接中使用常量值?

這是一個好方法。另外,還可以添加一列臨時裏面有cbind加入:

d1[cbind(d2, A = current.val), on=.(B = C, A), D := i.Z ] 

其實,c作品代替cbind這裏,但我覺得這是一個怪異的做法。

+0

我比我目前的做法更喜歡這個。它將附加列的範圍作爲其目的。我仍然覺得我錯過了一些不能直接在常量上過濾的東西 – Ethan

+0

@Ethan爲了過濾常量,我通常使用'd1 [。(current.val),on =。(A)]'。我想最終有可能在'on ='上寫一個常量,但現在它是一個相當新的功能......另外,我不確定我是否喜歡這個想法,因爲它非常適合設計。將所有與'x'或'i'連接的數據相關聯。 – Frank

+0

沒錯。它增加了使用':='回寫的複雜性,這使得這更復雜。我一直在'data.table'上掙扎的東西是子集規則在回寫':='操作符的上下文中並不總是以相同的方式工作。 – Ethan

0

對於剛剛五個行,它不會有任何區別,但如果你想擴大規模,則該操作會快很多,如果你對d1d2設置鍵:

d1 <- data.table(A=5:1, B=letters[5:1], key="B") 
d2 <- data.table(C=letters[5:1], Z=6:10, key="C") 

下面的結構然後會給出想要的結果:

d1[d1[d2][A==current.val], D := Z] 
+0

非常有趣的方法。我不確定dt如何優化交叉連接/過濾器/連接,因此我更新了示例以允許基準測試。解決方案(如初始示例所示)不會在更大的輸入集合下完成。另外關於D1的關鍵是真的是A,B。也有可能我搞砸了新的例子;) – Ethan

+0

隨着新的例子(1e8行) - 我不得不將(d,d)從(A,B)改爲(B,A)。有了這個改變,它在我的系統中約5秒鐘就能得到預期的結果。 – gcbenison

+0

所以,做了一些測試。對於我的現實世界的情況,我需要密鑰爲A,B。我嘗試添加一個索引'setindex(d1,B,A)',但那不起作用。我真的不明白爲什麼它可以與關鍵字一起使用,但不是索引,但這是一個單獨的問題。 (setkey(d1,B,A); d1 [d1 [d2] [A == current.val],D:= Z],這個解決方案本身速度快得多, ; setkey(d1,A,B)})'與temp列方法大致相同 – Ethan