为什么X [Y]连接data.tables不允许完全外连接或左连接?

Dou*_*ark 115 join r data.table

这是关于data.table连接语法的一个哲学问题.我发现data.tables的用途越来越多,但仍在学习......

X[Y]data.tables 的连接格式非常简洁,方便和高效,但据我所知,它只支持内连接和右外连接.要获得左外部或全外部连接,我需要使用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 = 0nomatch = NA参数值对于正在执行的操作不是非常直观.这是我更容易理解和记忆的merge语法:all = TRUE,all.x = TRUEall.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
Run Code Online (Sandbox Code Playgroud)

更新:data.table v1.9.6引入了on=语法,该语法允许在主键以外的字段上进行临时连接.jangorecki对问题如何连接(合并)数据框(内部,外部,左侧,右侧)的回答提供了data.table可以处理的其他连接类型的一些示例.

mne*_*nel 70

引用data.table FAQ 1.11 X[Y]merge(X, Y)?之间的区别是什么?

X[Y] 是一个连接,使用Y(或Y的键,如果有的话)作为索引查找X的行.

Y[X] 是一个连接,使用X查找Y的行(如果有X,则查找X的键)

merge(X,Y)同时做两种方式.行数X[Y]Y[X]通常不同,而返回的行数merge(X,Y)merge(Y,X)相同.

但是错过了重点.大多数任务需要在连接或合并后对数据执行某些操作.为什么要合并所有数据列,之后只使用它们中的一小部分?您可能会建议 merge(X[,ColsNeeded1],Y[,ColsNeeded2]),但这需要程序员确定需要哪些列.X[Y,j]在data.table中为您完成所有这一切.编写时X[Y,sum(foo*bar)],data.table会自动检查j表达式以查看它使用的列.它只会仅对这些列进行子集化; 其他人被忽略了.仅为j使用的列创建内存,并且Y列在每个组的上下文中享有标准R回收规则.假设fooX,并且bar在Y(以及其他20列Y)中.是不是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
Run Code Online (Sandbox Code Playgroud)

如果你想要一个完整的外部联接

# 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)]]
Run Code Online (Sandbox Code Playgroud)

  • 令我印象深刻的是data.table文件,它可以如此冗长,但仍然如此神秘...... (10认同)
  • 谢谢@mnel.FAQ 1.12未提及完全或左外连接.您对unique()的完整外部联接建议是一个很好的帮助.这应该在FAQ中.我知道Matthew Dowle"为自己设计它,他就是这么想的." (FAQ 1.9),但我认为`X [Y,all = T]`可以是在data.table X [Y]语法中指定完整外连接的优雅方式.或左边连接的`X [Y,all.x = T]`.我想知道为什么它不是这样设计的.只是一个想法. (5认同)
  • 什么是"J"? (2认同)
  • @mnel unique_keys &lt;- union(X[,t], Y[,t]) 会用更少的击键完成这项工作 (2认同)

Mat*_*wle 22

@ mnel的答案是现场,所以接受这个答案.这只是跟进,对于评论来说太长了.

作为MNEL说,左/右外连接是通过交换获得YX:Y[X]航班吗X[Y].因此,在该语法中支持4种连接类型中的3种,而不是2,iiuc.

添加第4个似乎是一个好主意.假设我们添加full=TRUE或者(both=TRUE或者merge=TRUE不确定最佳参数名称?)然后在我之前没有想到它X[Y,j,merge=TRUE]对于在FAQ 1.12中的BUT之后的原因有用.新功能请求现已添加并链接回此处,谢谢:

FR#2301:像merge()一样为X [Y]和Y [X]连接添加merge = TRUE参数.

最近的版本已经加速merge.data.table(例如,通过在内部采用浅拷贝来更有效地设置密钥).因此,我们正试图把merge()X[Y]密切,并提供给用户的所有选项充分的灵活性.两者都有利弊.另一项出色的功能要求是:

FR#2033:将by.x和by.y添加到merge.data.table

如果还有其他人,请保持他们的到来.

通过这部分问题:

为什么不使用合并语法进行连接而不是匹配函数的nomatch参数?

如果你喜欢merge()的语法和它的3个参数all,all.x并且all.y然后就用这个来代替X[Y].认为它应涵盖所有情况.或者你的意思是为什么这个论点是单一nomatch[.data.table?如果是这样的话,这就是常见问题解答2.14:"你能进一步解释为什么data.table受到基础中A [B]语法的启发吗?".而且,nomatch只需要目前两个值0NA.这可以延长,以便负值意味着某些东西,或者12意味着使用第12行的值来填充NA,例如,或者nomatch将来可能是向量甚至是自身a data.table.

嗯.by-without-by如何与merge = TRUE交互?也许我们应该把这个转到datatable-help.


Dou*_*ark 16

这个"答案"是一个讨论的提议:如我的评论中所示,我建议join在[.data.table()中添加一个参数以启用其他类型的连接,即:X[Y,j,join=string].除了4种类型的普通连接外,我还建议支持3种类型的独占连接和交叉连接.

join建议各种连接类型的字符串值(和别名)为:

  1. "all.y""right"- 右连接,当前data.table默认值(nomatch = NA) - 所有Y行与没有X匹配的NA;
  2. "both""inner" - 内连接(nomatch = 0) - 只有X和Y匹配的行;

  3. "all.x""left" - 左连接 - 来自X,NAs的所有行,其中没有Y匹配:

  4. "outer""full" - 完全外连接 - 来自X和Y的所有行,NAs不匹配

  5. "only.x""not.y"-非连接或反连接返回X行里没有ÿ匹配

  6. "only.y""not.x"-非连接或反连接返回y行不存在X匹配
  7. "not.both" - 独占连接返回X和Y行,其中与另一个表不匹配,即异或(XOR)
  8. "cross"- 交叉连接或笛卡尔积,每行X与Y的每一行匹配

默认值join="all.y"对应于当前默认值.

"all","all.x"和"all.y"字符串值对应于merge()参数."右","左","内"和"外"字符串可能更适合SQL用户.

"both"和"not.both"字符串是我目前最好的建议 - 但有人可能对内连接和独占连接有更好的字符串建议.(我不确定"独占"是否是正确的术语,如果有"XOR"连接的正确术语,请纠正我.)

使用join="not.y"是一种替代 X[-Y,j]X[!Y,j]无连接语法,也许更清楚(我),虽然我不知道他们是相同的(在data.table版本1.8.3的新功能).

交叉连接有时候很方便,但它可能不适合data.table范例.

  • +1但是,_please_要么发送到[datatable-help](http://r.789695.n4.nabble.com/datatable-help-f2315188.html),要么提交[功能请求](https:// r -forge.r-project.org/tracker/?group_id=240).我不介意添加`join`但除非它进入跟踪器,否则它会被遗忘. (3认同)
  • 请将其发送到[datatable-help](http://r.789695.n4.nabble.com/datatable-help-f2315188.html)进行讨论。 (2认同)
  • 我发现您已经有一段时间没有登录 SO 了。所以我已将其提交到 [FR#2301](https://r-forge.r-project.org/tracker/index.php?func=detail&amp;aid=2301&amp;group_id=240&amp;atid=978) (2认同)