首选使用哪种data.table语法进行左联接(一列)

时间:2019-01-22 16:10:21

标签: r data.table

我应该如何开始考虑我更喜欢哪种语法?

我的标准是效率(这是第一位)以及可读性/可维护性。

A <- B[A, on = .(id)] # wow such. concision

或者那个

A[B, on = .(id), comment := i.comment]

甚至(如PoGibas建议的那样):

A <- merge(A, B, all.x = TRUE)

为了完整起见,一种更基本的方法是使用match()

A[, comment := B[chmatch(A[["id"]], id), comment]]

示例数据:

library(data.table)
A <- data.table(id = letters[1:10], amount = rnorm(10)^2)
B <- data.table(id = c("c", "d", "e"), comment = c("big", "slow", "nice"))

1 个答案:

答案 0 :(得分:14)

为了效率和可维护性,我更喜欢“更新联接”的习惯用法:**

DT[WHERE, v := FROM[.SD, on=, x.v]]

它是vignette("datatable-reference-semantics")中“通过引用更新某些列的行-通过引用 sub-assign ”显示的内容的扩展。一旦在连接上有一个小插图可用,那也应该是一个很好的参考。

这是有效的,因为它仅使用WHERE选择的行并就地修改或添加该列,而不是像更简洁的左联接FROM[DT, on=]那样创建新表。

这使我的代码更具可读性,因为我可以很容易地看到联接的重点是添加列v;而且我不必考虑SQL中的“左” /“右”行话,也不必考虑联接后是否保留行数。

这对代码维护很有用,因为如果以后我想找出DT如何获得名为v的列,则可以在我的代码中搜索v :=,而{{1} }掩盖了要添加的新列。另外,它允许使用FROM[DT, on=]条件,而左联接则不允许。例如,如果using FROM to "fill" NAs in an existing column v,这可能很有用。


与其他更新联接方法WHERE相比,我可以想到两个优点。第一种是使用DT[FROM, on=, v := i.v]子句的选项,第二种是在连接出现问题时通过警告(例如,以WHERE为条件的FROM中的重复匹配)来通过警告透明。这是扩展OP示例的图示:

on=

在左联接风格的更新中,即使library(data.table) A <- data.table(id = letters[1:10], amount = rnorm(10)^2) B2 <- data.table( id = c("c", "d", "e", "e"), ord = 1:4, comment = c("big", "slow", "nice", "nooice") ) # left-joiny update A[B2, on=.(id), comment := i.comment, verbose=TRUE] # Calculated ad hoc index in 0.000s elapsed (0.000s cpu) # Starting bmerge ...done in 0.000s elapsed (0.000s cpu) # Detected that j uses these columns: comment,i.comment # Assigning to 4 row subset of 10 rows # my preferred update A[, comment2 := B2[A, on=.(id), x.comment]] # Warning message: # In `[.data.table`(A, , `:=`(comment2, B2[A, on = .(id), x.comment])) : # Supplied 11 items to be assigned to 10 items of column 'comment2' (1 unused) id amount comment comment2 1: a 0.20000990 <NA> <NA> 2: b 1.42146573 <NA> <NA> 3: c 0.73047544 big big 4: d 0.04128676 slow slow 5: e 0.82195377 nooice nice 6: f 0.39013550 <NA> nooice 7: g 0.27019768 <NA> <NA> 8: h 0.36017876 <NA> <NA> 9: i 1.81865721 <NA> <NA> 10: j 4.86711754 <NA> <NA> 有两个匹配项,您也默默地获得了comment的最终值;而在其他更新中,您会收到一条有用的警告消息(已升级为an error in a future release)。甚至使用左联接方法打开id == "e"也不提供信息-它说有四行被更新,但没有说一行被更新了两次。


我发现,当我的数据排列在一组整洁/关系表中时,这种方法最有效。 Hadley Wickham's paper是一个很好的参考。

**在此惯用语中,verbose=TRUE部分应使用连接列名称和规则(例如on=on=.(id))填充。可以使用on=.(from_date >= dt_date)roll=mult=传递更多的加入规则。有关详细信息,请参见nomatch=。感谢@RYoda在评论中指出这一点。

这里是Matt Dowle解释?data.tableFind time to nearest occurrence of particular value for each row

时更复杂的示例