【发布时间】:2014-02-21 12:10:37
【问题描述】:
概述
我对@987654334@ 比较熟悉,对dplyr 不太熟悉。我已经阅读了一些 dplyr vignettes 和 SO 上出现的示例,到目前为止,我的结论是:
-
data.table和dplyr在速度上相当,除非有很多(即 >10-100K)组,以及在某些其他情况下(请参阅下面的基准) -
dplyr具有更易于访问的语法 -
dplyr抽象(或将要)潜在的数据库交互 - 存在一些细微的功能差异(请参阅下面的“示例/用法”)
在我看来 2. 没有太大分量,因为我对它相当熟悉 data.table,尽管我知道对于这两者的新手来说,这将是一个重要因素。我想避免争论哪个更直观,因为这与我从已经熟悉 data.table 的人的角度提出的具体问题无关。我也想避免讨论“更直观”如何导致更快的分析(当然是真的,但同样,这不是我最感兴趣的)。
问题
我想知道的是:
- 对于熟悉软件包的人来说,是否有更容易使用一个或另一个软件包编写代码的分析任务(例如,所需的击键与所需的深奥水平的某种组合,其中少一些是好事)。
- 是否有分析任务在一个包中比在另一个包中的执行效率显着提高(即超过 2 倍)。
一个recent SO question 让我对这个问题有了更多的思考,因为在此之前,我认为dplyr 不会提供超出我在data.table 中已经可以做的事情。这是dplyr 解决方案(Q 末尾的数据):
dat %.%
group_by(name, job) %.%
filter(job != "Boss" | year == min(year)) %.%
mutate(cumu_job2 = cumsum(job2))
这比我对data.table 解决方案的破解尝试要好得多。也就是说,好的data.table 解决方案也非常好(感谢 Jean-Robert、Arun,并注意这里我更喜欢单一语句而不是严格最优的解决方案):
setDT(dat)[,
.SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)],
by=list(id, job)
]
后者的语法可能看起来很深奥,但如果您习惯了data.table(即不使用一些更深奥的技巧),它实际上非常简单。
理想情况下,我希望看到一些很好的例子,例如 dplyr 或 data.table 方式更简洁或性能更佳。
示例
用法-
dplyr不允许返回任意行数的分组操作(来自 eddi's question,注意:这看起来将在 dplyr 0.5 中实现,此外, @beginneR 在@eddi 的问题的答案中展示了使用do的潜在解决方法。 -
data.table支持 rolling joins(感谢@dholstius)以及 overlap joins -
data.table在内部优化DT[col == value]或DT[col %in% values]形式的表达式以实现 speed 通过 自动索引 使用 二分搜索 同时使用相同基本 R 语法。 See here 了解更多细节和小基准。 -
dplyr提供函数的标准评估版本(例如regroup、summarize_each_),可以简化dplyr的编程使用(注意data.table的编程使用绝对是可能的,只需要仔细考虑,替换/引用等,至少据我所知)
- 我运行了 my own benchmarks 并发现两个包在“拆分应用组合”样式分析中具有可比性,除非此时有大量组 (>100K)
data.table变得更快。 - @Arun 运行了一些 benchmarks on joins,表明随着组数量的增加,
data.table的扩展性优于dplyr(更新为包和 R 的最新版本中的最新增强功能)。此外,在尝试获得 unique values 时的基准测试使data.table的速度提高了约 6 倍。 - (未验证)
data.table在较大版本的组/应用/排序上快 75%,而dplyr在较小版本上快 40%(another SO question from comments,感谢 danas) . -
data.table的主要作者Matt,拥有benchmarked grouping operations ondata.table,dplyrand pythonpandason up to 2 billion rows (~100GB in RAM)。 -
older benchmark on 80K groups 比
data.table快 8 倍左右
数据
这是我在问题部分展示的第一个示例。
dat <- structure(list(id = c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L,
2L, 2L, 2L, 2L, 2L, 2L), name = c("Jane", "Jane", "Jane", "Jane",
"Jane", "Jane", "Jane", "Jane", "Bob", "Bob", "Bob", "Bob", "Bob",
"Bob", "Bob", "Bob"), year = c(1980L, 1981L, 1982L, 1983L, 1984L,
1985L, 1986L, 1987L, 1985L, 1986L, 1987L, 1988L, 1989L, 1990L,
1991L, 1992L), job = c("Manager", "Manager", "Manager", "Manager",
"Manager", "Manager", "Boss", "Boss", "Manager", "Manager", "Manager",
"Boss", "Boss", "Boss", "Boss", "Boss"), job2 = c(1L, 1L, 1L,
1L, 1L, 1L, 0L, 0L, 1L, 1L, 1L, 0L, 0L, 0L, 0L, 0L)), .Names = c("id",
"name", "year", "job", "job2"), class = "data.frame", row.names = c(NA,
-16L))
【问题讨论】:
-
与
dplyr类似的解决方案是:as.data.table(dat)[, .SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)], by = list(name, job)] -
好吧,再次提醒,
(d)plyr中更清晰地表达的问题集的度量为 0 -
@BrodieG 关于
dplyr和plyr在语法方面真正困扰我的一件事,基本上是我不喜欢它们的语法的主要原因,我也必须学习许多(阅读超过 1 个)额外的函数(名称对我来说仍然没有意义),记住它们的作用,它们采用的参数等。这一直是一个巨大的关闭对我来说来自 plyr 哲学。 -
@eddi [tongue-in-cheek] data.table 语法真正困扰我的一件事是,我必须了解太多函数参数如何交互,以及神秘的快捷方式意味着什么(例如
.SD)。 [认真] 我认为这些是合理的设计差异,会吸引不同的人 -
@hadley re
.SD等 - 这很公平 -.SD花了我一点时间来理解,但是当我到达那里时,我已经能够做很多事情了,而( d)plyr 为您提供了一个巨大的障碍。
标签: r data.table dplyr