53

注意:这个问题和以下答案是指 data.table 版本 < 1.5.3;v. 1.5.3 于 2011 年 2 月发布以解决此问题。查看更多最新处理(03-2012):将外键上的 SQL 连接转换为 R data.table 语法


我一直在研究data.table 包的文档(替代 data.frame 对某些操作更有效),包括Josh Reich 在 NYC R Meetup 上关于 SQL 和 data.table 的演示(pdf),但是无法弄清楚这个完全微不足道的操作。

> x <- DT(a=1:3, b=2:4, key='a')
> x
     a b
[1,] 1 2
[2,] 2 3
[3,] 3 4
> y <- DT(a=1:3, c=c('a','b','c'), key='a')
> y
     a c
[1,] 1 a
[2,] 2 b
[3,] 3 c
> x[y]
     a b
[1,] 1 2
[2,] 2 3
[3,] 3 4
> merge(x,y)
  a b c
1 1 2 a
2 2 3 b
3 3 4 c

文档说“当 [第一个参数] 本身是一个 data.table 时,调用类似于 base::merge 的连接,但在排序键上使用二进制搜索。” 显然情况并非如此。我可以使用 data.tables 将 y 中的其他列转换为 x[y] 的结果吗?似乎它只是取 x 的行,其中键与 y 的键匹配,但完全忽略了 y 的其余部分......

4

4 回答 4

29

您引用了文档的错误部分。如果您查看文档,[.data.table您将阅读:

当 i 是 data.table 时,x 必须有一个键,这意味着将 i 连接到 x 并返回 x 中匹配的行。在 i 中的每一列到 x 的键中的每一列之间按顺序执行 equi-join。这类似于通过 2 列矩阵对矩阵进行子集的基本 R 功能,并且在更高维度中通过 n 列矩阵对 n 维数组进行子集

我承认包的描述(你引用的部分)有点令人困惑,因为它似乎说可以使用“[”-操作而不是合并。但我认为它说的是:如果 x 和 y 都是 data.tables,我们在索引上使用连接(像合并一样调用)而不是二进制搜索。


还有一件事:

我通过安装的 data.table 库install.packages缺少merge.data.table method,因此使用merge会调用merge.data.frame. 从 R-Forge安装软件包后, R 使用了更快的merge.data.table方法。

您可以通过检查以下输出来检查您是否具有 merge.data.table 方法:

methods(generic.function="merge")

编辑 [答案不再有效]:这个答案是指 data.table 版本 1.3。在 1.5.3 版本中,data.table 的行为发生了变化,x[y] 返回了预期的结果。感谢data.table 的作者Matthew Dowle在评论中指出这一点。

于 2010-02-10T13:58:44.070 回答
15

感谢您的回答。当它最初发布时,我错过了这个线程。自 2 月以来,data.table 已继续前进。1.4.1 不久前发布到 CRAN,1.5 即将发布。例如 DT() 别名已被替换为 list();作为一个原语,它的速度要快得多,并且 data.table 现在继承自 data.frame,因此它适用于接受 data.frame 的包,例如 ggplot 和 lattice,无需任何转换(更快更方便)。

是否可以订阅 data.table 标签,以便在有人使用该标签发布问题时收到电子邮件?数据表帮助列表已增长到每月大约 30-40 条消息,但如果我能得到某种通知,我也很乐意在这里回答。

马修

于 2010-07-27T13:22:49.413 回答
13

我认为base::merge不需要使用该功能,因为使用data.table连接可以快得多。例如,请参阅以下内容。我用 3-3 列制作xydata.tables:

x <- data.table( foo = 1:5, a=20:24, zoo = 5:1 )
y <- data.table( foo = 1:5, b=30:34, boo = 10:14)
setkey(x, foo)
setkey(y, foo)

并合并 withbase:mergedata.tablejoins 以查看执行速度:

system.time(merge(x,y))
##    user  system elapsed 
##   0.027   0.000   0.023 

system.time(x[,list(y,x)])
##    user  system elapsed 
##   0.003   0.000   0.006 

结果并不相同,因为后者有一个额外的列:

merge(x,y)
##      foo  a zoo  b boo
## [1,]   1 20   5 30  10
## [2,]   2 21   4 31  11
## [3,]   3 22   3 32  12
## [4,]   4 23   2 33  13
## [5,]   5 24   1 34  14

x[,list(x,y)]
##      foo  a zoo foo.1  b boo
## [1,]   1 20   5     1 30  10
## [2,]   2 21   4     2 31  11
## [3,]   3 22   3     3 32  12
## [4,]   4 23   2     4 33  13
## [5,]   5 24   1     5 34  14

这不会造成大麻烦:)

于 2011-01-22T09:28:47.683 回答
3

我认为 f3lix 是正确的,并且文档有点误导。好处是进行快速连接以对数据进行子集化。之后您仍然最终需要使用该merge功能,如上面的示例所示。

您将在Josh 关于使用 data.table 的演示文稿中看到,这就是他的示例的运行方式。他首先对其中一个 data.tables 进行子集化,然后进行合并:

library(data.table)
sdt <- DT(series, key='series_id')
ddt <- DT(data, key='series_id')
u <- sdt[ grepl('^[A-Z]{2}URN', fred_id) & !grepl('DSURN', fred_id) ]
d <- ddt[ u, DT(min=min(value)), by='series_id', mult='all']
data <- merge(d,series)[,c('title','min','mean','max')]
于 2010-02-10T14:06:45.183 回答