为啥 data.table 的 inner_join 行为不同?

Posted

技术标签:

【中文标题】为啥 data.table 的 inner_join 行为不同?【英文标题】:Why does inner_join behave differently for data.table?为什么 data.table 的 inner_join 行为不同? 【发布时间】:2014-11-15 18:49:20 【问题描述】:

我想使用dplyr 函数inner_join() 将数据框与数据表连接起来。这是我的代码。

library(data.table)
library(dplyr)

DF <- data.frame(x = rep( c("a","b","c"), each=3), 
                 y = rep( c(1,3,6), 3))

DT <- data.table(x = rep( c("a","b","c"), each=3), 
                 y = rep( c(1,3,6), 3))

W <- data.frame(x = c("b","c","d"), 
              foo = c(4,2,9))

当我尝试加入两个数据框时,inner_join() 可以正常工作。

inner_join(DF,W)

Joining by: "x"
  x y foo
1 b 1   4
2 b 3   4
3 b 6   4
4 c 1   2
5 c 3   2
6 c 6   2

但是当我尝试将数据框与数据表连接时,inner_join() 给出了意外的结果。

inner_join(DT,W)

Joining by: "x"
  x y foo
1 b 1   2
2 b 3   2
3 b 6   2
4 c 1   9
5 c 3   9
6 c 6   9

谁能给我一些提示,为什么会发生这种情况?提前感谢您的宝贵时间。

注意:我在 MAC Maverick OS X 10.9.4 上使用 RStudio 版本 0.98.1056,sessionInfo()

R version 3.1.1 (2014-07-10)
Platform: x86_64-apple-darwin13.1.0 (64-bit)

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] dplyr_0.2        data.table_1.9.2

loaded via a namespace (and not attached):
[1] assertthat_0.1 parallel_3.1.1 plyr_1.8.1     Rcpp_0.11.2    reshape2_1.4  
[6] stringr_0.6.2  tools_3.1.1   

【问题讨论】:

这是因为data.table 中的一个错误导致将character 类与factor 类合并时导致错误结果。尝试将DT 更改为DT &lt;- data.table(x = factor(rep( c("a","b","c"), each=3)), y = rep( c(1,3,6), 3)),然后再次尝试inner_join(DT,W) 感谢@DavidArenburg,您的评论解决了我的问题。 要清楚一点,而@DavidArenburg 的评论(部分)是正确的,因为当x 的键列是一个因素并且对应的i 的列是字符时,x[i] 返回结果不正确(这是 data.table 中的一个错误),它是一个 red herring,与您的示例无关。而是由于 dplyr 中的一个错误,此后该错误已得到修复。 【参考方案1】:

David 提到的因素和字符列之间的bug in data.table 是正确的,但它仍然没有修复。但不幸的是,这是一个红鲱鱼,并且不是你的麻烦之源。

但是,这是因为dplyr v0.2中没有inner_join.data.table方法,因此它调用了inner_join.data.frame方法(因为data.table也是data.frame)。

require(dplyr) ## 0.2 CRAN
require(data.table) ## 1.9.2

methods(inner_join)
# [1] inner_join.data.frame* inner_join.tbl_df*     inner_join.tbl_dt*    
# [4] inner_join.tbl_sql*  

因此,当你这样做时:

inner_join(DF, W)

inner_join(DT, W)

两者都调用相同的dplyr's 内部连接实现。

它给出不同结果的原因是因为DFW 都将x 作为因子,而DTx 作为字符列。

您可以通过将DF$x 更改为字符类型来重现此错误:

DF$x = as.character(DF$x)
inner_join(DF, W)
# Joining by: "x"
#   x y foo
# 1 b 1   2
# 2 b 3   2
# 3 b 6   2
# 4 c 1   9
# 5 c 3   9
# 6 c 6   9

但这似乎已经在dplyr的开发版本中得到修复。

【讨论】:

感谢@Arun 的精彩解释。这真的帮助我理解了@David 的评论。我对data.table 的理解是它也是data.frame。现在,如果data.frame 默认读取文本作为因子,data.table 不应该默认做同样的事情吗?还是我还缺少什么? 大卫的评论与您的​​问题无关。请再次阅读答案 大卫的建议解决了我的问题。我同意他的第一条评论可能不是我问题的根源。 这似乎在开发版中得到了修复(至少现在有inner_join.data.table 的方法)。

以上是关于为啥 data.table 的 inner_join 行为不同?的主要内容,如果未能解决你的问题,请参考以下文章

为啥中位数跳闸 data.table (整数与双精度)?

为啥在分组 data.table 中的 lm 上使用更新会丢失其模型数据?

为啥 data.table::B[A] 和 plyr::join(A,B) 返回不同的结果?

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

在`dt2 <- dt %>% myfun`中,为啥要修改dt? [复制]

对象比相应的 .RData 文件大得多。为啥?可以手动做吗?