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 <- 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 而无需重新复制的主要内容,如果未能解决你的问题,请参考以下文章
NodeJS 和 Mongoose:将元素添加到现有的空数组