Performance 从data.table和data.frame对象获取单个元素所需的时间
在我的工作中,我通常有几个表(客户详细信息、交易记录等)。由于其中一些非常大(数百万行),我最近切换到了Performance 从data.table和data.frame对象获取单个元素所需的时间,performance,r,dataframe,data.table,Performance,R,Dataframe,Data.table,在我的工作中,我通常有几个表(客户详细信息、交易记录等)。由于其中一些非常大(数百万行),我最近切换到了data.table包(谢谢Matthew)。但是,其中一些非常小(数百行和4/5列),并且被多次调用。因此,我开始考虑[.data.table检索数据时的开销,而不是像?set中已经清楚描述的那样设置()值,其中,不管表的大小,一个项目的设置时间大约为2微秒(取决于cpu) 然而,它似乎不存在从数据表中获取值的集合等价物,因为它知道确切的行和列。一种可循环的[.data.table libr
data.table
包(谢谢Matthew)。但是,其中一些非常小(数百行和4/5列),并且被多次调用。因此,我开始考虑[.data.table
检索数据时的开销,而不是像?set
中已经清楚描述的那样设置()值,其中,不管表的大小,一个项目的设置时间大约为2微秒(取决于cpu)
然而,它似乎不存在从数据表
中获取值的集合
等价物,因为它知道确切的行和列。一种可循环的[.data.table
library(data.table)
library(microbenchmark)
m = matrix(1,nrow=100000,ncol=100)
DF = as.data.frame(m)
DT = as.data.table(m) # same data used in ?set
> microbenchmark(DF[3450,1] , DT[3450, V1], times=1000) # much more overhead in DT
Unit: microseconds
expr min lq median uq max neval
DF[3450, 1] 32.745 36.166 40.5645 43.497 193.533 1000
DT[3450, V1] 788.791 803.453 813.2270 832.287 5826.982 1000
> microbenchmark(DF$V1[3450], DT[3450, 1, with=F], times=1000) # using atomic vector and
# removing part of DT overhead
Unit: microseconds
expr min lq median uq max neval
DF$V1[3450] 2.933 3.910 5.865 6.354 36.166 1000
DT[3450, 1, with = F] 297.629 303.494 305.938 309.359 1878.632 1000
> microbenchmark(DF$V1[3450], DT$V1[3450], times=1000) # using only atomic vectors
Unit: microseconds
expr min lq median uq max neval
DF$V1[3450] 2.933 2.933 3.421 3.422 40.565 1000 # DF seems still a bit faster (23%)
DT$V1[3450] 3.910 3.911 4.399 4.399 16.128 1000
最后一种方法确实是将单个元素快速检索几次的最佳方法。但是,set
甚至更快
> microbenchmark(set(DT,1L,1L,5L), times=1000)
Unit: microseconds
expr min lq median uq max neval
set(DT, 1L, 1L, 5L) 1.955 1.956 2.444 2.444 24.926 1000
问题是:如果我们能够在2.444微秒内设置一个值,那么我们就不可能在更短(或至少类似)的时间内获得一个值?谢谢
编辑:
根据建议,添加另外两个选项:
> microbenchmark(`[.data.frame`(DT,3450,1), DT[["V1"]][3450], times=1000)
Unit: microseconds
expr min lq median uq max neval
`[.data.frame`(DT, 3450, 1) 46.428 47.895 48.383 48.872 2165.509 1000
DT[["V1"]][3450] 20.038 21.504 23.459 24.437 116.316 1000
不幸的是,这并不比以前的尝试快。多亏了@hadley,我们才有了解决方案
> microbenchmark(DT$V1[3450], set(DT,1L,1L,5L), .subset2(DT, "V1")[3450], times=1000, unit="us")
Unit: microseconds
expr min lq median uq max neval
DT$V1[3450] 2.566 3.208 3.208 3.528 27.582 1000
set(DT, 1L, 1L, 5L) 1.604 1.925 1.925 2.246 15.074 1000
.subset2(DT, "V1")[3450] 0.000 0.321 0.322 0.642 8.339 1000
但我有点怀疑你对重复子集的需求。这通常意味着你可以通过改变算法来优化。@Arun@Roland感谢大家的关注。关于Roland的观点,我认为他在大多数情况下是正确的。即使对我来说,也意味着重新设计整个解决方案。然而,我的问题正是你所想的阅读最后一行,这也是基于M Dowle的想法,即拥有一个“可循环的”:=
,它是集
+1。对于您的用例(“几百行和4/5列”,这应该占用少量内存),也许您可以将小数据表的副本存储为矩阵,并在访问元素时使用后者…?在我的计算机上,m[3450,1]
仍然比DT$V1[3450]快约10倍
;我认为只有矩阵才能实现这种性能。另一方面,矩阵中的每一列都需要有相同的类……试试。subset2(DT,“V1”)[3450]
-。subset2
是的内部版本[[
这不会执行S3调度,而且速度更快。@hadley非常感谢。您的评论确实是答案。为什么不在下面编写您的解决方案呢?谢谢。