基于列名合并data.table

14
我正在尝试使用data.tables进行一些左连接合并。该软件包的描述引用了以下内容:
在所有连接中,列的名称都不重要;按顺序连接x的关键列
我知道可以使用.data.table[]和data.table :::merge.data.table。
我的需求是:指定键(类似于基本合并中的by.x和by.y)合并X和Y。
假设我有:
DT = data.table(x=rep(c("a","b","c"),each=3),y=c(1,3,6),v=1:9,key="x,y,v")
DT1 = data.frame(x1=c("aa","bb","cc"),y1=c(1,3,6),v1=1:3,key="x1,y1,v1")

我希望您能将此输出:

#data.table:::merge is masking I don't know how to call the base version of merge anymore
R) {base::merge}(DT,DT1,by.x="y",by.y="y1") 
y x v x1 v1
1 1 a 1 aa  1
2 1 c 7 aa  1
3 1 b 4 aa  1
4 3 a 2 bb  2
5 3 b 5 bb  2
6 3 c 8 bb  2
7 6 b 6 cc  3
8 6 a 3 cc  3
9 6 c 9 cc  3

我很高兴使用[data.table:::merge,但我希望有一个选项不修改DTDT1(比如更改列名并调用合并,然后再改回来)。


2
merge.data.table是S3通用基础函数merge的一种方法。要调用基础合并函数,可以使用merge.data.frame(DT,DT1,by.x="y",by.y="y1")。但也请参考我的答案。 - Matt Dowle
请查看这篇新帖子:使用data-table进行内外连接以合并NA - statquant
顺便说一下,我刚刚注意到你在Nabble上尝试两次发布datatable-help的帖子。它们没有通过(请参见Nabble顶部的黄色条),因为您需要先订阅datatable-help。在发布时,Nabble会询问您“您是否是要发布的列表的成员”。加入很容易且自动化,这只是一项垃圾邮件预防措施。 - Matt Dowle
我知道这已经很老了,但是重命名其中一个数据表的列以匹配另一个数据表不应该是可行的吗?我尝试使用setnames来实现这一点,但出现了错误,但我不明白为什么它不能工作。 - willwest
3个回答

9

更新: 自从data.table v1.9.6(于2015年9月19日发布)起,merge.data.table()接受并很好地处理by.x=by.y=参数。 这里是更新后的链接,指向下面提到的已关闭的FR。


是的,这是一个尚未实现的功能请求:

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

没有任何阻止它的东西。 只是某件尚未完成的事情。 我很少需要merge,而且很慢才意识到其更广泛的有用性。 我们在将merge性能提高到与X[Y]一样快方面取得了良好的进展,此功能请求处于最高优先级。 如果您希望更快地使用它,则可以将这些参数添加到merge.data.table中并提交更改。 我们试图保持源代码简短且集中在一个函数/文件中,因此通过查看merge.data.table源代码,您可以跟随它并了解需要完成哪些工作。


我可以试着看一下(虽然可能超出我的水平),不过我想我需要设置一个svn/git... - statquant
我怀疑这不会超出你的水平,合并的源代码只是R和X[Y]调用,而你已经开始了解它们。挑战一下可能是一个很好的练习。如果data.table在GitHub上,你会觉得更容易吗? - Matt Dowle
你能读到下面的消息吗?因为我担心 Y[X] 本身(或者是一个特性)有 bug,但是如果你看下面的左外连接,Y[X] 显示了不应该出现的行 :( (我希望我是错的) - statquant
@statquant 哎呀,忽略之前的长评论吧。我没有仔细看。它似乎匹配不正确,是吗?比我想象的更糟糕。我会去看看... - Matt Dowle
是的,我认为存在问题,在左外连接中匹配似乎有误,因为在第1行depID=NA时,depName被赋值为Eng,在第2行name=Raf时,它失去了depName(应该是Sal而不是NA)。 - statquant
显示剩余2条评论

5

现在,在data.table的开发版本中,参数by.xby.y已经可用。请参见此处。使用devtools::install_github("Rdatatable/data.table", build_vignettes = FALSE)安装data.table的开发版本。


感谢您提供有用的PR。 - David Arenburg
这是现在的版本1.9.6。 - Ben

4

你不能这样做,因为按列拼接的数据必须在DT和DT1的列名交集中。

 if (!all(by %in% intersect(colnames(x), colnames(y)))) {
       stop("Elements listed in `by` must be valid column names in x and y")
   }

在这里使用setnames,它不会复制并且非常快速。
setnames(DT1,'y1','y')
> merge(DT,DT1)
   y x v x1 v1
1: 1 a 1 aa  1
2: 1 b 4 aa  1
3: 1 c 7 aa  1
4: 3 a 2 bb  2
5: 3 b 5 bb  2
6: 3 c 8 bb  2
7: 6 a 3 cc  3
8: 6 b 6 cc  3
9: 6 c 9 cc  3

编辑,使用data.table 1.9.4版本更新

如果不设置by参数,则会出现错误:

Error in merge.data.table(DT, as.data.table(DT1)) : 
  Elements listed in `by` must be valid column names in x and y

你应该像这样做:
merge(DT,DT1,by="y")

是的,但是我还需要重新设置列名... 是否有一种使用 [ 的方法,因为我可能需要 nomatch 选项? - statquant
@statquant 我需要调查一下'['的解决方案。我还不是data.table的用户。你想要'['是因为它更优雅吗? - agstudy
实际上,[merge 更快,因为 merge 查找 XYdata.table 在合并方面不是很清楚,缺乏一个好的 FAQ-merge。 - statquant
@statquant同意,data.table缺少很多东西:例如,有104个功能请求未完成。尽管其中许多实际上是TODO项目而不是特定的功能。 - Matt Dowle
1
@matthew 我正在研究合并,我认为我发现了一个错误(可能是一个特性),因为merge.data.tablemerge.data.frame对于外部左连接和右连接的输出结果不同。 - statquant
@statquant 好的,我会看一下。如果可能的话,向datatable-help发送电子邮件询问是否存在错误是最好的方法。在S.O.上提出的问题不应该是“特定于某个时间点”的 - 这是关闭问题的原因之一。如果我理解正确的话,这是S.O.的礼仪。但就个人而言,我不介意任何方法,只要能够感激地接收到错误报告即可。 - Matt Dowle

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接