【发布时间】:2021-08-12 01:19:32
【问题描述】:
我创建了一些代码,我需要在大约 1M 行的循环中进行大量连接。起初我使用左连接制作浅拷贝,但我更改了代码以进行更新连接,它变得很慢。
一些测试数据
a=data.table(id=1:10^6)
b=data.table(id=1:10^6, t='y')
cols=setdiff(names(b),names(a))
c=copy(b[a,on=.(id)])
a[b,(cols):=mget(cols),on=.(id)]
all.equal(a,c)
[1]TRUE
我不知道这是否是比较时间的正确方法,但这里是
浅拷贝
microbenchmark(c=b[a,on=.(id)])
Unit: milliseconds
expr min lq mean median uq max neval
c 120.5911 122.734 128.1071 124.0922 126.1449 179.0127 100
更新 data.table
microbenchmark(a[b,(cols):=mget(cols),on=.(id)])
Unit: milliseconds
expr min lq mean median uq max
a[b, `:=`((cols), mget(cols)), on = .(id)] 159.6128 162.9798 175.9855 168.5807 184.8756 308.5406
neval
100
虽然我需要一个解决方案来更新多个列,但不知道为什么,但是使用 mget 比下面的方法慢
microbenchmark(a[b, t:=i.t, on=.(id)])
Unit: milliseconds
expr min lq mean median uq max neval
a[b, `:=`(t, i.t), on = .(id)] 138.0173 140.4671 146.3558 141.6204 143.281 185.1488 100
在这种情况下,我不关心内存使用,只关心速度。有没有比复制方法更快地更新原始表而不复制的方法?
【问题讨论】:
-
不要使用 mget,因为它可能效率低下,请改用 env var
-
@jangorecki 我将研究环境,但你能提供一些如何使用它的例子吗?我在一个函数中使用它,其中
colschange 中的名称基于用户提供的值。我现在对mget有另一个疑问,不知道您是否可以帮助我,但是如果我在函数内部使用它并且在函数外部具有相同的对象名称,它将始终访问在函数内部创建的对象?我做了一些测试,发生了什么,但阅读帮助并不清楚。 -
@jangorecki,虽然我熟悉 envvars(
..varname表示上一级访问)并且新了解 wipenv=list(...)参数,但我无法获得类似dfa[dfb, c(cols) := .(..cols), on = .(id)]的信息正常工作。我猜这是一个我没有看到的微妙问题,但我认为如果您可以扩展您的第一条评论,这将非常有帮助。谢谢! (R.Cowboy,我将变量重命名为dfa和dfb,因为我真的不喜欢在 R 中有一个名为c的对象,所以我将这三个都重命名。) -
另见stackoverflow.com/questions/60263274/…。
mget很慢,因为内部代码需要为.SD变量分配内存。我将发布一个对用户不太友好的解决方案env = list(...)。 -
env arg 只是使用基本 R 替代品的友好方式,@Cole 答案很棒!
标签: r data.table