我该如何开始考虑我更喜欢哪种语法?
我的标准是效率(这是第一)以及可读性/可维护性.
这个
A <- B[A, on = .(id)] # wow such. concision
Run Code Online (Sandbox Code Playgroud)
或者那个
A[B, on = .(id), comment := i.comment]
Run Code Online (Sandbox Code Playgroud)
甚至(正如PoGibas所说):
A <- merge(A, B, all.x = TRUE)
Run Code Online (Sandbox Code Playgroud)
为了完整性,一个更基本的方法是使用match():
A[, comment := B[chmatch(A[["id"]], id), comment]]
Run Code Online (Sandbox Code Playgroud)
示例数据:
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"))
Run Code Online (Sandbox Code Playgroud)
Fra*_*ank 15
为了提高效率和可维护性,我更喜欢"更新连接"这个用语:**
DT[WHERE, v := FROM[.SD, on=, x.v]]
Run Code Online (Sandbox Code Playgroud)
它是vignette("datatable-reference-semantics")"通过引用更新一些列的行 - 按引用子分配 "中显示的内容的扩展.一旦联接上有一个小插图,这也应该是一个很好的参考.
这是有效的,因为它只使用选择的行WHERE并就地修改或添加列,而不是像新的简洁左连接那样创建新表FROM[DT, on=].
它使我的代码更具可读性,因为我可以很容易地看到连接点是添加列v; 而且我不需要考虑SQL中的"左"/"右"术语,或者在连接后是否保留行数.
它对于代码维护很有用,因为如果我后来想知道如何DT命名列v,我可以搜索我的代码v :=,同时FROM[DT, on=]模糊添加了哪些新列.此外,它允许WHERE条件,而左连接则不允许.例如,如果用于"填充"现有列中的NA,这可能很有用FROMv.
与其他更新连接方法相比DT[FROM, on=, v := i.v],我可以想到两个优点.第一个是使用该WHERE子句的选项,第二个是当连接出现问题时通过警告透明,例如以FROM条件为条件的重复匹配on=.以下是扩展OP示例的说明:
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>
Run Code Online (Sandbox Code Playgroud)
在左连接风格的更新中,comment即使有两个匹配项,您也会静默获取最终值id == "e".在另一个更新中,您会收到一条有用的警告消息(在将来的版本中升级为错误).即使verbose=TRUE使用左连接方法启用也没有提供信息 - 它说有四行正在更新,但并没有说一行正在更新两次.
我发现当我的数据被安排到一组整洁/关系表中时,这种方法效果最好.对此的一个很好的参考是Hadley Wickham的论文.
**在这个成语中,on=应该使用连接列名称和规则填充该部分,例如on=.(id)或on=.(from_date >= dt_date).而且加入的规则可以被传递roll=,mult=和nomatch=.详情?data.table请见.感谢@RYoda在评论中注意到这一点.