【问题标题】:Evaluate at which size data.table is faster than data.frame评估 data.table 比 data.frame 快的大小
【发布时间】:2013-11-24 15:43:28
【问题描述】:

有人可以帮我评估一下使用 data.table 的数据框大小对搜索来说更快吗?在我的用例中,数据框将是 24,000 行和 560,000 行。总是挑选出 40 行的块以供进一步使用。

示例: DF 是一个 120 行 7 列(x1 到 x7)的数据框; "string" 占据 x1 的前 40 行。

DF2 是 DF 的 1000 倍 => 120,000 行

DF data.table 的大小比较慢,DF2 的大小比较快。

代码:

> DT <- data.table(DF)
> setkey(DT, x1)
> 
> DT2 <- data.table(DF2)
> setkey(DT2, x1)
> 
> microbenchmark(DF[DF$x1=="string", ], unit="us")
Unit: microseconds
                    expr     min       lq   median       uq     max neval
 DF[DF$x1 == "string", ] 282.578 290.8895 297.0005 304.5785 2394.09   100
> microbenchmark(DT[.("string")], unit="us")
Unit: microseconds
            expr      min       lq  median      uq      max neval
 DT[.("string")] 1473.512 1500.889 1536.09 1709.89 6727.113   100
> 
> 
> microbenchmark(DF2[DF2$x1=="string", ], unit="us")
Unit: microseconds
                      expr     min       lq   median       uq      max neval
 DF2[DF2$x1 == "string", ] 31090.4 34694.74 35537.58 36567.18 61230.41   100
> microbenchmark(DT2[.("string")], unit="us")
Unit: microseconds
             expr      min       lq   median       uq      max neval
 DT2[.("string")] 1327.334 1350.801 1391.134 1457.378 8440.668   100

【问题讨论】:

  • +1。也许只是使用 data.table 但对其应用不同的子集函数,从列表methods(`[`) 中选择?此外,如果您想要一个实质性的答案,您可能需要为 DF 和 DF2 创建示例数据
  • @Frank:我尝试了 subset(DT2[.("string")]) ,它有点慢。这就是你的想法吗? DF 数据:x1:字符串,40 行始终相同,x2:字符串,x3 到 x7:日期。 DF2 只是 DF 复制了 1000 次。我需要选择具有相同字符串的 40 行。
  • 我在想,如果你的数据太小以至于 data.frame 子集是合适的,你总是可以做 `[.data.frame`(DT,DT$x1=="string") 或类似的事情,并将你的数据保存在 data.table 中。另外,如果x1=="string" 为前 40 行,您应该只选择前 40 行,对吗?
  • 如果“字符串”在前 40 行中,我猜 data.frame(执行行搜索)将具有类似于 data.table 的性能......你应该做一些更随机的事情......

标签: r data.table


【解决方案1】:
library(microbenchmark)
library(data.table)
timings <- sapply(1:10, function(n) {
  DF <- data.frame(id=rep(as.character(seq_len(2^n)), each=40), val=rnorm(40*2^n), stringsAsFactors=FALSE)
  DT <- data.table(DF, key="id")     
  tofind <- unique(DF$id)[n-1]
  print(microbenchmark( DF[DF$id==tofind,],
                        DT[DT$id==tofind,],
                        DT[id==tofind],
                        `[.data.frame`(DT,DT$id==tofind,),
                        DT[tofind]), unit="ns")$median
})

matplot(1:10, log10(t(timings)), type="l", xlab="log2(n)", ylab="log10(median (ns))", lty=1)
legend("topleft", legend=c("DF[DF$id == tofind, ]",
                           "DT[DT$id == tofind, ]",
                           "DT[id == tofind]",
                           "`[.data.frame`(DT,DT$id==tofind,)",
                           "DT[tofind]"),
       col=1:5, lty=1)

一月。 2016:更新到data.table_1.9.7

data.table 在编写后进行了一些更新([.data.table 增加了一些开销,因为内置了更多参数/稳健性检查,而且还引入了自动索引)。以下是来自 GitHub 的 2016 年 1 月 13 日版本 1.9.7 的更新版本:

主要创新是第三个选项现在利用了自动索引。主要结论保持不变 - 如果您的表具有任何不平凡的大小(大约大于 500 个观察值),data.table 的帧内调用会更快。

(关于更新图的注释:一些小事(不记录 y 轴,以微秒表示,更改 x 轴标签,添加标题),但我更新了一件不平凡的事情microbenchmarks 以在估计中增加一些稳定性——即,我将 times 参数设置为 as.integer(1e5/2^n))

【讨论】:

  • @Frank 是的,确实如此(正如预期的那样)。
  • 我认为使用普通的data.table 语法会快一点:DT[id == tofind],因为您不必调用$
  • @chriscross 是的,我认为这就是要点,尽管我认为 data.tables 出于其他原因也更可取(更好的语法,其他快速的操作......),所以我会说你只是放弃香草data.frames是安全的。 (顺便说一下,data.tables 只是一种特殊类型的 data.frame;这就是 `[.data.frame` 对它们起作用的原因。)
  • @eddi 这似乎无关紧要。
  • @MichaelChirico 和 Roland:很有趣。 +1。在这里发推文:twitter.com/MattDowle/status/687397266513072129
猜你喜欢
  • 2019-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多