data.table 连接然后将列添加到现有的 data.frame 而无需重新复制

Posted

技术标签:

【中文标题】data.table 连接然后将列添加到现有的 data.frame 而无需重新复制【英文标题】:data.table join then add columns to existing data.frame without re-copy 【发布时间】:2013-11-02 09:32:13 【问题描述】:

我有两个data.tables,X(3m 行,约 500 列)和 Y(100 行,两列)。

set.seed(1)
X <- data.table( a=letters, b=letters, c=letters, g=sample(c(1:5,7),length(letters),replace=TRUE), key="g" )
Y <- data.table( z=runif(6), g=1:6, key="g" )

我想在 X 上做一个左外连接,我可以通过 Y[X] 来做,感谢:

Why does X[Y] join of data.tables not allow a full outer join, or a left join?

但我想将新列添加到X 而不复制X(因为它很大)。

显然,X &lt;- Y[X] 之类的东西有效,但除非data.table 比我认为的聪明得多(而且我认为它非常狡猾!),我相信这复制了整个@987654330 @。

X[ , z:= Y[X,z]$z ] 有效,但是很笨拙,不能很好地扩展到一列以上。

我如何以一种有效的方式(在副本和程序员时间方面)将合并的结果存储回保留的 data.table 中?

【问题讨论】:

你不需要做Y[X,z](如果你忘记了by-without-by,这样做可能会遇到问题),只需X[, z := Y[X]$z] 工作并且似乎更快例子;虽然最终X = Y[X] 是迄今为止我尝试过的不同表达方式中最快的 有趣。我在那里有,z,因为我认为这会给 DT 提供关于它需要保留哪些变量的信息,因为它对此进行了优化。但是你的(删除的)点值得在这里复制:“当像Y[X,z] 那样做某事时,请注意隐藏的by-without-by。”即使它很快,如果X = Y[X] 创建一个副本我可能会遇到麻烦.... 我明白了,所以您关心的更多是内存使用和速度降低;在那种情况下,我认为你所建议的,以你所建议的形式,尽管如此(好吧,我认为 - 我总是对此感到困惑),可能是要走的路 如果我改用Y[X,list(z)],我是否需要担心? 相关并由 eddi 回答,尽管没有人找到文档:***.com/questions/16843728/… 【参考方案1】:

这很容易做到:

X[Y, z := i.z]

之所以有效,是因为这里Y[X]X[Y] 之间的唯一区别是某些元素不在Y 中,在这种情况下,您可能希望z 成为NA,即上面的分配就可以了。

它也适用于许多变量:

X[Y, `:=`(z1 = i.z1, z2 = i.z2, ...)]

由于您需要操作Y[X],因此您可以添加参数nomatch=0(正如@mnel 指出的那样),以免X 不包含来自Y 的键值的那些获得NA。即:

X[Y, z := i.z, nomatch=0]

来自NEWS for data.table

    **********************************************
    **                                          **
    **   CHANGES IN DATA.TABLE VERSION 1.7.10   **
    **                                          **
    **********************************************

新功能

o   The prefix i. can now be used in j to refer to join inherited
    columns of i that are otherwise masked by columns in x with
    the same name.

【讨论】:

非常感谢。这有效(即使使用我编辑的示例数据),但我不明白为什么。 i. 符号有名称吗?我在?[.data.table....的任何地方都没有看到它。 我认为 i. 的使用记录很差,我忘记了它现在在哪里 - 但它只是用来引用 i-expression data.table 的列 我明白了。对于为什么X[Y](右外连接)产生与X[Y, z:= i.z](左外连接和赋值)产生如此不同的结果仍然有点困惑。 就连接而言,它们都产生相同的结果,在第二种情况下,来自Y 的结果z 被分配给X 中的一个新列(它会自动产生NA 用于不匹配的情况) @AriB.Friedman -- 它在 1.7.10 版的新闻中(我添加了一个链接)。对于差异,归结为您不能通过引用添加行(还),因此X[Y, z:=i.z] 将等同于设置z=i.z X[Y, z:=iz, nomatch=0]` 【参考方案2】:

作为上述答案的补充,您还可以这样做(v1.9.6+):

require(data.table) # v1.9.6+
X[Y, (colNames) := mget(paste0("i.", colNames))]

其中colNames 是一个字符向量,列出了您想要从Y 获得的列。这使您可以在添加许多列的情况下有效地选择要添加的列(从names(Y) 的子集中定义colNames)。

此外,您可以将其与新的 on= 参数(来自 v1.9.6+)组合为:

# ad-hoc joins using 'on=' instead of setting keys
require(data.table) # v1.9.6+
X[Y, (colNames) := mget(paste0("i.", colNames)), on = "g"]

(colNames) := mget(colNames) 策略在此归功于 akrun:Update rows of data frame in R。

【讨论】:

其实不是akrun,而是你楼上的人在这里介绍的:***.com/a/30469832/3001626。所以基本上这个线程上的两个答案都是eddi的

以上是关于data.table 连接然后将列添加到现有的 data.frame 而无需重新复制的主要内容,如果未能解决你的问题,请参考以下文章

将带有数据的新表包含到现有的 Debezium 连接器中

将列并行分配给 data.table

将文本插入到现有的大文件中

NodeJS 和 Mongoose:将元素添加到现有的空数组

使用 rstan::rstan.package.skeleton 添加到现有的 R 包

如何以编程方式将数据库添加到现有的 Always On 可用性组 (AOAG)?