这是关于data.table连接语法的一个哲学问题 . 我发现data.tables的用途越来越多,但仍在学习......
data.tables的连接格式 X[Y]
非常简洁,方便和高效,但据我所知,它只支持内连接和右外连接 . 要获得左外部或全外部连接,我需要使用 merge
:
-
X[Y, nomatch = NA]
- Y中的所有行 - 右外连接(默认) -
X[Y, nomatch = 0]
- 仅在X和Y中都匹配的行 - 内部联接 -
merge(X, Y, all = TRUE)
- 来自X和Y的所有行 - 完全外部连接 -
merge(X, Y, all.x = TRUE)
- X中的所有行 - 左外连接
在我看来,如果 X[Y]
连接格式支持所有4种类型的连接,它会很方便 . 有没有理由只支持两种类型的连接?
对我来说, nomatch = 0
和 nomatch = NA
参数值对于正在执行的操作不是非常直观 . 我更容易理解并记住 merge
语法: all = TRUE
, all.x = TRUE
和 all.y = TRUE
. 由于 X[Y]
操作类似 merge
比 match
更多,为什么不使用 merge
语法进行连接而不是 match
函数的 nomatch
参数呢?
以下是4种连接类型的代码示例:
# sample X and Y data.tables
library(data.table)
X <- data.table(t = 1:4, a = (1:4)^2)
setkey(X, t)
X
# t a
# 1: 1 1
# 2: 2 4
# 3: 3 9
# 4: 4 16
Y <- data.table(t = 3:6, b = (3:6)^2)
setkey(Y, t)
Y
# t b
# 1: 3 9
# 2: 4 16
# 3: 5 25
# 4: 6 36
# all rows from Y - right outer join
X[Y] # default
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
X[Y, nomatch = NA] # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
merge(X, Y, by = "t", all.y = TRUE) # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
# 3: 5 NA 25
# 4: 6 NA 36
identical(X[Y], merge(X, Y, by = "t", all.y = TRUE))
# [1] TRUE
# only rows in both X and Y - inner join
X[Y, nomatch = 0]
# t a b
# 1: 3 9 9
# 2: 4 16 16
merge(X, Y, by = "t") # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
merge(X, Y, by = "t", all = FALSE) # same as above
# t a b
# 1: 3 9 9
# 2: 4 16 16
identical( X[Y, nomatch = 0], merge(X, Y, by = "t", all = FALSE) )
# [1] TRUE
# all rows from X - left outer join
merge(X, Y, by = "t", all.x = TRUE)
# t a b
# 1: 1 1 NA
# 2: 2 4 NA
# 3: 3 9 9
# 4: 4 16 16
# all rows from both X and Y - full outer join
merge(X, Y, by = "t", all = TRUE)
# t a b
# 1: 1 1 NA
# 2: 2 4 NA
# 3: 3 9 9
# 4: 4 16 16
# 5: 5 NA 25
# 6: 6 NA 36
更新:data.table v1.9.6引入了 on=
语法,该语法允许在主键以外的字段上进行临时连接 . jangorecki's answer问题How to join (merge) data frames (inner, outer, left, right)?提供了data.table可以处理的其他连接类型的一些示例 .
3 回答
引用
data.table
FAQ 1.11 What is the difference between X[Y] and merge(X, Y)?如果你想要一个左外连接
X[Y]
如果你想要一个完整的外部联接
@ mnel的答案是现场,所以接受这个答案 . 这只是跟进,对于评论来说太长了 .
正如mnel所说,左/右外连接是通过交换
Y
和X
:Y[X]
-vs-X[Y]
获得的 . 因此,在该语法中支持4种连接类型中的3种,而不是2,iiuc .添加第4个似乎是一个好主意 . 假设我们添加
full=TRUE
或both=TRUE
或merge=TRUE
(不确定最佳参数名称?)然后在我之前没有想到X[Y,j,merge=TRUE]
在FAQ 1.12中的BUT之后会有用 . 新功能请求现已添加并链接回此处,谢谢:FR#2301 : Add merge=TRUE argument for both X[Y] and Y[X] join like merge() does.
最近的版本加快了
merge.data.table
(例如,在内部采用浅拷贝来更有效地设置键) . 所以我们试图让merge()
和X[Y]
更接近,并为用户提供所有选项以获得充分的灵活性 . 两者都有利弊 . 另一项出色的功能要求是:FR#2033 : Add by.x and by.y to merge.data.table
如果还有其他人,请保持他们的到来 .
通过这部分问题:
如果您更喜欢
merge()
语法及其3个参数all
,all.x
和all.y
,那么只需使用它而不是X[Y]
. 认为它应涵盖所有情况 . 或者你的意思是为什么这个论点在[.data.table
中是单个nomatch
?如果是这样的话,这就是常见问题解答2.14:"Can you explain further why data.table is inspired by A[B] syntax in base?" . 但是,nomatch
目前只有两个值0
和NA
. 可能被延长以便负值意味着什么,或者12意味着使用第12行的值来填充NA,例如,或者nomatch
将来可能是一个向量甚至本身就是data.table
.嗯 . by-without-by如何与merge = TRUE交互?也许我们应该把这个拿到datatable-help .
这个"answer"是一个讨论提案:如我的评论所示,我建议在[.data.table()中添加
join
参数以启用其他类型的连接,即:X[Y,j,join=string]
. 除了4种类型的普通连接外,我还建议支持3种类型的独占连接和交叉连接 .建议各种连接类型的
join
字符串值(和别名)为:"all.y"
和"right"
- 右连接,当前data.table默认值(nomatch = NA) - 所有带有NA的Y行,其中没有X匹配;"both"
和"inner"
- 内连接(nomatch = 0) - 只有X和Y匹配的行;"all.x"
和"left"
- 左连接 - X,NAs中没有Y匹配的所有行:"outer"
和"full"
- 全外连接 - 来自X和Y的所有行,NAs不匹配"only.x"
和"not.y"
- 非连接或反连接返回没有Y匹配的X行"only.y"
和"not.x"
- 非连接或反连接返回Y行,其中没有X匹配"not.both"
- 独占连接返回X和Y行,其中与其他表不匹配,即异或(XOR)"cross"
- 交叉连接或笛卡尔积,每行X与Y的每一行匹配默认值为
join="all.y"
,对应于当前默认值 ."all","all.x"和"all.y"字符串值对应于
merge()
参数 . "right","left","inner"和"outer"字符串可能更适合SQL用户 .“both”和“not.both”字符串是我目前最好的建议 - 但有人可能对内连接和独占连接有更好的字符串建议 . (我不确定“独占”是否是正确的术语,如果有“XOR”连接的正确术语,请纠正我 . )
使用
join="not.y"
是X[-Y,j]
或X[!Y,j]
非连接语法的替代方法,可能更清楚(对我而言),虽然我不确定它们是否相同(data.table版本1.8.3中的新功能) .交叉连接有时候很方便,但它可能不适合data.table范例 .