概述
我比较熟悉data.table
,不太了解dplyr
。我已经阅读了一些出现在 SO 上的dplyr
小插曲和示例,到目前为止,我的结论是:
data.table
并且dplyr
在速度上具有可比性,除非有许多(即 >10-100K)组,以及在某些其他情况下(参见下面的基准)dplyr
具有更易于访问的语法dplyr
抽象(或将要)潜在的数据库交互- 有一些小的功能差异(请参阅下面的“示例/用法”)
在我看来 2. 并没有太大的分量,因为我对它相当熟悉data.table
,尽管我知道对于这两者的新手来说,这将是一个重要因素。我想避免争论哪个更直观,因为这与我从已经熟悉的人的角度提出的具体问题无关data.table
。我也想避免讨论“更直观”如何导致更快的分析(当然是真的,但同样,这不是我在这里最感兴趣的)。
问题
我想知道的是:
- 对于熟悉这些软件包的人来说,是否有更容易使用一个或另一个软件包编写代码的分析任务(即所需的击键与所需的深奥水平的某种组合,其中较少的每个都是一件好事)。
- 是否存在在一个包中比在另一个包中更有效地执行的分析任务(即超过 2 倍)。
最近的一个SO 问题让我对此进行了更多思考,因为在此之前,我认为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
ordata.table
方法更简洁或性能更好。
例子
用法dplyr
不允许返回任意行数的分组操作(来自eddi 的问题,请注意:这看起来将在dplyr 0.5中实现,此外,@beginneR 显示了do
在@eddi 问题的答案中使用的潜在解决方法)。data.table
支持滚动连接(感谢@dholstius)以及重叠连接data.table
通过使用二分搜索同时使用相同的基本 R 语法的自动索引在内部优化表单的表达式DT[col == value]
或DT[col %in% values]
提高速度。有关更多详细信息和一个小基准,请参见此处。dplyr
提供标准评估版本的函数(例如regroup
,summarize_each_
),可以简化编程使用dplyr
(注意编程使用data.table
绝对是可能的,只需要仔细考虑,替换/引用等,至少据我所知)
- 我运行了自己的基准测试,发现这两个包在“拆分应用组合”样式分析中具有可比性,除非有大量组(> 100K),此时
data.table
会变得更快。 - @Arun在 joins 上运行了一些基准测试,表明随着组数的增加(随着包和 R 的最新版本的最新增强而更新),它的
data.table
扩展性更好。dplyr
此外,尝试获取唯一值时的基准测试速度提高了data.table
约 6 倍。 - (未经验证)
data.table
在较大版本的组/应用/排序上快 75%,而在较小版本上dplyr
快 40%(来自评论的另一个 SO 问题,感谢 danas)。 - 的主要作者 Matt对多达 20 亿行(RAM 中约 100GB)上的分组操作和 python
data.table
进行了基准测试。data.table
dplyr
pandas
- 80K 组的旧基准测试速度提高了
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))