R - 创建大量data.table对象时性能缓慢

17

我当然知道data.table对象的主要目的是允许快速的子集/分组等操作,拥有一个大的data.table并对其进行子集操作(非常高效)比拥有大量(可能很小)的data.table对象更有意义。

话虽如此,我最近创建了一个脚本,实例化了许多data.table对象,我注意到随着内存中data.table的数量增加,性能会下降。

以下是我所指的示例:

n <- 10000
# create a list containing 10k data.frame's
system.time(lotsofDFs <- lapply(1:n,FUN=function(i){ data.frame(A=1:10,B=1:10,ID=i)}),gcFirst=T)
#   user  system elapsed 
#   2.24    0.00    2.23 
# create a list containing 10k data.table's
system.time(lotsofDTs <- lapply(1:n,FUN=function(i){ data.table(A=1:10,B=1:10,ID=i)}),gcFirst=T)
#   user  system elapsed 
#   5.49    0.01    5.53 
n <- 80000
# create a list containing 80k data.frame's
system.time(lotsofDFs <- lapply(1:n,FUN=function(i){ data.frame(A=1:10,B=1:10,ID=i)}),gcFirst=T)
#   user   system elapsed
#   19.42    0.01   19.53
# create a list containing 80k data.table's
system.time(lotsofDTs <- lapply(1:n,FUN=function(i){ data.table(A=1:10,B=1:10,ID=i)}),gcFirst=T)
#   user    system elapsed
#   147.03    0.10  147.41

正如您所注意到的,虽然data.frame的创建时间随着创建的data.frame数量呈线性增长,但data.table的复杂度似乎超过了线性。
这是预期的吗?
这是否与内存中表格列表有关(可以通过调用tables()函数查看)?
环境: R版本3.1.2(Windows上)
data.table 1.9.4
编辑: 正如@Arun在评论中指出的那样,as.data.table(...)的行为似乎类似于data.frame(...)。实际上,矛盾的是,as.data.table(data.frame(...))data.table(...)更快,并且时间随对象数量呈线性增长,例如:
n <- 10000
# create a list containing 10k data.table's using as.data.table
system.time(lotsofDTs <- lapply(1:n,FUN=function(i){ as.data.table(data.frame(A=1:10,B=1:10,ID=i))}),gcFirst=T)
#   user  system elapsed 
#   5.04    0.01    5.04 
n <- 80000
# create a list containing 80k data.table's using as.data.table
system.time(lotsofDFs <- lapply(1:n,FUN=function(i){ as.data.table(data.frame(A=1:10,B=1:10,ID=i))}),gcFirst=T)
#   user   system elapsed
#   44.94    0.12   45.28

1
这可能非常依赖于系统。在前两个上,我得到了df和dt分别为2.35和2.82。 - Señor O
6
你运行了 Rprof() 吗?它应该会显示在 alloc.col 中花费的时间(列指针过度分配)... :curious: 那么你用那 50K 个 data.table 做什么呢?我的意思是,需要那么多对象的任务是什么? - Arun
1
@digEmAll,大部分时间都花在了.Call上 - 它是从alloc.col内部调用的。所以,我非常确定它对于10K+表格做出了相当大的贡献。对于您的情况,我建议将它们存储为list()对象(因为它们是原始数据),特别是如果您不对它们进行任何类似于data.table的操作..然后使用rbindlist()将它们合并.. - 它也接受列表的列表。 - Arun
1
@Arun:就像我说的,我正在重构代码,所以我不认为我还需要这么多的 data.table 了...不管怎样,谢谢你的提示(当然也感谢您在 data.table 包上的工作) :) - digEmAll
我可以建议另一种方法,使用setDT。在我的机器上,性能非常接近于data.frame的性能,35秒(data.frame)vs 38秒(setDT)vs 506秒(data.table)。我正在使用data.table 1.10.4(在Linux上):system.time(lotsofDFs <- lapply(1:n,FUN = function(i){a <- data.frame(A = 1:10,B = 1:10,ID = i); setDT(a); a}),gcFirst = T) - Picarus
显示剩余7条评论
1个回答

1
你应该使用 setDT

n <- 80000
system.time(lotsofDTs <- lapply(1:n,FUN=function(i){setDT(list(A=1:10,B=1:10,ID=matrix(i,10)))}),gcFirst=T)
#   user  system elapsed 
#   6.75    0.28    7.17

system.time(lotsofDFs <- lapply(1:n,FUN=function(i){ data.frame(A=1:10,B=1:10,ID=i)}),gcFirst=T)
#   user  system elapsed 
#  32.58    1.40   34.22 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接