为什么data.tables的X [Y]连接不允许完整的外连接或左连接?
这是关于data.table连接语法的一个哲学问题。 我正在为data.tables找到越来越多的用途,但仍然在学习......
data.tables的连接格式X[Y]
非常简洁,方便和高效,但据我所知,它只支持内连接和右外连接。 要获得左或全外连接,我需要使用merge
:
X[Y, nomatch = NA]
- Y中的所有行 - 右外部X[Y, nomatch = NA]
(默认) 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
match
参数?
以下是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对问题的回答如何连接(合并)数据框架(内部,外部,左侧,右侧)? 提供了data.table可以处理的其他连接类型的一些示例。
引用data.table常见问题解答1.12
1.12
X [Y]和merge(X,Y)有什么区别?
X[Y]
是一个连接,使用Y(或Y的键,如果它有一个)作为索引查找X的行。 Y[X]
是一个连接,使用X查找Y的行(或X的键,如果它有一个) merge(X,Y)
执行两种方式。 X[Y]
和Y[X]
的行数通常不同; 而merge(X,Y)
和merge(Y,X)
返回的行数相同。 但错过了主要观点。 加入或合并后,大多数任务都需要对数据执行一些操作。 为什么要合并所有的数据列,只能在事后使用它们的一小部分? 您可能会建议merge(X[,ColsNeeded1],Y[,ColsNeeded2])
,但需要复制子数据集的副本,并且它要求程序员确定需要哪些列。 data.table中的X[Y,j
]为您完成所有步骤。 当你写X[Y,sum(foo*bar)]
,data.table将自动检查j表达式以查看它使用的列。 它只会对这些列进行分组; 其他人被忽略。 内存仅为j使用的列创建,Y列在每个组的上下文中享受标准R回收规则。 假设foo在X中,而bar在Y中(Y中还有20个其他列)。 是不是X[Y,sum(foo*bar)]
更快,而且比之后的子集更快?
如果您想要X[Y]
的左外部连接,
le <- Y[X]
mallx <- merge(X, Y, all.x = T)
# the column order is different so change to be the same as `merge`
setcolorder(le, names(mallx))
identical(le, mallx)
# [1] TRUE
如果你想要一个完整的外连接
# the unique values for the keys over both data sets
unique_keys <- unique(c(X[,t], Y[,t]))
Y[X[J(unique_keys)]]
## t b a
## 1: 1 NA 1
## 2: 2 NA 4
## 3: 3 9 9
## 4: 4 16 16
## 5: 5 25 NA
## 6: 6 36 NA
# The following will give the same with the column order X,Y
X[Y[J(unique_keys)]]
@ 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之后。 现在添加新功能请求并将其链接回来,谢谢:
FR#2301:为X [Y]和Y [X]连接添加merge = TRUE参数,就像merge()一样。
最近的版本加快了merge.data.table
(例如,通过内部浅拷贝来更有效地设置密钥)。 所以我们试图让merge()
和X[Y]
更接近,并为用户提供所有选项以获得充分的灵活性。 两者都有优点和缺点。 另一个突出的功能要求是:
FR#2033:将by.x和by.y添加到merge.data.table
如果有其他人,请保持他们来。
通过这部分的问题:
为什么不使用合并语法而不是匹配函数的不匹配参数?
如果您更喜欢merge()
语法及其3个参数all
, all.x
和all.y
那么只需使用它而不是X[Y]
。 认为它应该涵盖所有的情况。 还是你的意思是为什么的说法单nomatch
在[.data.table
? 如果是这样,那么FAQ2.14看起来很自然:“你能否进一步解释为什么data.table是基于A [B]语法的启发?”。 而且,不nomatch
只有0
和NA
两个值。 这可能会延长,所以负值意味着什么,或者12将意味着使用第12行的值来填充NA,例如,或者将来可能不nomatch
可能是矢量,或者甚至本身是data.table
。
嗯。 by-without-by如何与merge = TRUE交互? 也许我们应该把这个转到数据表的帮助。
这个“答案”是一个讨论的建议:正如我的评论所指出的,我建议在[.data.table()中添加一个join
参数以启用其他类型的连接,即: X[Y,j,join=string]
。 除了4种常规联接之外,我还建议支持3种类型的联合联接和交叉联接。
建议各种连接类型的join
字符串值(和别名)为:
"all.y"
和"right"
- 右连接,当前data.table默认值(nomatch = NA) - 所有Y行与NAs没有X匹配; "both"
和"inner"
- 内连接(nomatch = 0) - 只有X和Y匹配的行;
"all.x"
和"left"
- 左连接 - 来自X的所有行,没有Y匹配的NA:
"outer"
和"full"
- 完整的外连接 - X和Y的所有行,不匹配的NAs
"only.x"
和"not.y"
- 非连接或反连接返回没有Y匹配的X行
"only.y"
和"not.x"
- 在没有X匹配的情况下,非连接或反连接返回Y行 "not.both"
- 独占连接返回与其他表不匹配的X和Y行,即异或(XOR) "cross"
- 交叉连接或笛卡尔乘积与X的每一行匹配到Y的每一行 默认值是join="all.y"
,它对应于当前的默认值。
“all”,“all.x”和“all.y”字符串值对应于merge()
参数。 “右”,“左”,“内”和“外”字符串可能更适合SQL用户。
“both”和“not.both”字符串是我目前最好的建议 - 但是对于内部联接和独占联接,有人可能会有更好的字符串建议。 (我不确定“独占”是否是正确的术语,如果有适合“异或”连接的术语,请纠正我。)
使用join="not.y"
是X[-Y,j]
或X[!Y,j]
非连接语法的替代方法,对我来说可能更清晰,尽管我不确定它们是否是相同(data.table版本1.8.3中的新功能)。
交叉连接有时可能非常方便,但它可能不适合data.table范例。
链接地址: http://www.djcxy.com/p/24917.html上一篇: Why does X[Y] join of data.tables not allow a full outer join, or a left join?