【问题标题】:Time in getting single elements from data.table and data.frame objects从 data.table 和 data.frame 对象中获取单个元素的时间
【发布时间】:2013-05-28 17:40:58
【问题描述】:

在我的工作中,我曾经有几个表(客户详细信息、交易记录等)。由于其中一些非常大(数百万行),我最近切换到data.table 包(感谢 Matthew)。但是,其中一些非常小(几百行和 4/5 列)并且被多次调用。因此,我开始考虑 检索 数据中的[.data.table 开销,而不是像?set 中已经清楚描述的那样设置()值,其中,无论表的大小,一项都设置在 2 左右微秒(取决于 CPU)。

但是,它似乎不存在与set 等效的方法,用于从知道确切行和列的data.table 获取值。一种 loopable [.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

问题是:如果我们可以set 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

不幸的是,这并不比之前的尝试快。

【问题讨论】:

  • 但我有点怀疑您认为需要重复子集。这通常意味着您可以通过更改算法进行优化。
  • @Arun @Roland 感谢大家的关注。关于罗兰的观点,我想说他在大多数情况下都是对的。即使对我来说意味着重新设计整个解决方案。然而,我的问题正是你在最后一行读到的,这也是基于 M Dowle 的想法,即拥有一个“可循环”:=,即set
  • +1。对于您的用例(“几百行和 4/5 列”,这应该占用少量内存),也许您可​​以将小型 data.tables 的副本存储为矩阵,并在您需要时使用后者访问元素...?在我的电脑上,m[3450,1] 仍然比 DT$V1[3450] 快约 10 倍;我认为除了矩阵之外,您将无法实现这种性能。另一方面,矩阵中的每一列都需要具有相同的类...
  • 试试.subset2(DT, "V1")[3450] - .subset2[[ 的内部版本,它不进行 S3 调度,而且速度更快。
  • @hadley 非常感谢。您的评论确实是答案。你为什么不在下面写下你的解决方案?谢谢。

标签: performance r dataframe data.table


【解决方案1】:

感谢@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

【讨论】:

    猜你喜欢
    • 2015-02-28
    • 2017-05-26
    • 2018-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多