如果我在datatable语法的基础上使用dplyr语法,那么在仍然使用dplyr语法的情况下,我是否获得了datatable的所有速度优势?换句话说,如果我用dplyr语法查询数据表,我是否会误用它?或者我需要使用纯数据表语法来利用它的所有功能.

提前谢谢你的建议.代码示例:

library(data.table)
library(dplyr)

diamondsDT <- data.table(ggplot2::diamonds)
setkey(diamondsDT, cut) 

diamondsDT %>%
    filter(cut != "Fair") %>%
    group_by(cut) %>%
    summarize(AvgPrice = mean(price),
                 MedianPrice = as.numeric(median(price)),
                 Count = n()) %>%
    arrange(desc(Count))

结果:

#         cut AvgPrice MedianPrice Count
# 1     Ideal 3457.542      1810.0 21551
# 2   Premium 4584.258      3185.0 13791
# 3 Very Good 3981.760      2648.0 12082
# 4      Good 3928.864      3050.5  4906

这是我提出的数据表等价性.不确定是否符合DT良好实践.但我想知道,在幕后,代码是否真的比dplyr语法更有效:

diamondsDT [cut != "Fair"
        ] [, .(AvgPrice = mean(price),
                 MedianPrice = as.numeric(median(price)),
                 Count = .N), by=cut
        ] [ order(-Count) ]

推荐答案

没有直接/简单的答案,因为这两个包的理念在某些方面有所不同.因此,一些妥协是不可避免的.以下是您可能需要解决/考虑的一些问题.

Operations involving i (== filter() and slice() in dplyr)

假设DT,比如10列.考虑这些数据.表表达式:

DT[a > 1, .N]                    ## --- (1)
DT[a > 1, mean(b), by=.(c, d)]   ## --- (2)

(1) 给出列a > 1所在的DT中的行数.(2) 对于i中与(1)相同的表达式,返回由c,d分组的mean(b).

常用的dplyr个表达是:

DT %>% filter(a > 1) %>% summarise(n())                        ## --- (3) 
DT %>% filter(a > 1) %>% group_by(c, d) %>% summarise(mean(b)) ## --- (4)

显然是数据.表格代码较短.此外,它们也是more memory efficient1.为什么?因为在(3)和(4)中,filter()首先返回rows for all 10 columns,而在(3)中,我们只需要行数,在(4)中,我们只需要b, c, d列来进行后续操作.要克服这一点,我们必须事先:

DT %>% select(a) %>% filter(a > 1) %>% summarise(n()) ## --- (5)
DT %>% select(a,b,c,d) %>% filter(a > 1) %>% group_by(c,d) %>% summarise(mean(b)) ## --- (6)

必须强调两个方案之间的一个主要哲学差异:

  • data.table中,我们希望将这些相关操作放在一起,这样就可以查看j-expression(来自同一个函数调用),并意识到(1)中不需要任何列.计算i中的表达式,.N只是给出行数的逻辑向量的和;整个子集从未实现.在(2)中,只有第b,c,d列在子集中具体化,其他列被忽略.

  • 但在dplyr中,哲学是让函数精确地做一件事well.(至少目前)无法判断filter()之后的操作是否需要我们筛选的所有列.如果你想高效地完成这些任务,你需要提前思考.我个人觉得在这种情况下这是反直觉的.

请注意,在(5)和(6)中,我们仍然将不需要的第a列作为子集.但我不知道如何避免这种情况.如果filter()函数有一个参数来 Select 要返回的列,我们可以避免这个问题,但是该函数不会只执行一个任务(这也是dplyr设计的 Select ).

通过引用分配

dplyr将通过引用进行更新.这是两个软件包之间的另一个巨大(哲学)差异.

例如,在数据中.你可以做什么

DT[a %in% some_vals, a := NA]

只在满足条件的行上更新列a by reference.目前dplyr深度复制整个数据.表内部添加一个新列@布罗迪格在回答中已经提到了这一点.

但在实现FR #617时,深度拷贝可以被浅层拷贝取代.也相关:dplyr: FR#614.请注意,您修改的列将始终被复制(因此速度较慢/内存效率较低).无法通过引用更新列.

其他功能

  • 在数据中.由于这是一个中间过程,所以你永远无法理解这个结果.以this post为例.你(现在)不能吗使用dplyr的数据来实现这一点.表/数据.框架语法.

  • 数据dplyr的语法也不支持table的rolling joins功能.

  • 我们最近在数据中实现了重叠连接.表在区间范围内连接(here's an example),目前这是一个单独的函数foverlaps(),因此可以与管道操作员一起使用(magrittr/pipeR?-我从未try 过).

    但最终,我们的目标是将其集成到[.data.table中,以便我们可以获得其他功能,如分组、加入时聚合等..其限制条件与上述相同.

  • 从1.9.4开始,数据.表使用辅助键实现自动索引,用于基于常规R语法的快速二进制搜索子集.Ex:DT[x == 1]DT[x %in% some_vals]将在第一次运行时自动创建索引,然后使用二进制搜索将索引用于从同一列到快速子集的连续子集.这一功能将继续发展.此功能的概述为this gist.

    从数据实现filter()的方式来看.表,它没有利用这个功能.

  • dplyr的一个特性是,它还提供了interface to databases个使用相同语法的数据.桌子现在不好.

因此,你必须权衡这些(可能还有其他几点),并根据这些权衡是否为你所接受来决定.


(1) 请注意,内存效率直接影响速度(尤其是当数据变得更大时),因为在大多数情况下,瓶颈是将数据从主存移动到缓存(并尽可能多地利用缓存中的数据,减少缓存未命中率,从而减少对主存的访问).这里不谈细节.

R相关问答推荐

R的法国工作日

在之前合并的数据.tables中分配新列后.internal.selfref无效

创建计数(带重置)变量

如何创建具有总计列和ggplot 2所有条线的百分比标签的堆叠条形图?

如果窗口在CLARME或集团之外,则有条件领先/滞后滚动总和返回NA

R中的枢轴/转置

更改绘图上的x轴断点,而不影响风险?

根据R中两个变量的两个条件删除带有dspirr的行

过滤器数据.基于两列的帧行和R中的外部向量

R函数,用于生成伪随机二进制序列,其中同一数字在一行中不出现超过两次

使用data.table::fcase()而不是dplyr::case_When()时保持值

如何基于两个条件从一列中提取行

如何在R库GoogleDrive中完全删除预先授权的Google帐户?

在GG图中绘制射线的自动程序

R-按最接近午夜的时间进行筛选

如何使用For-R循环在向量中找到一系列数字

扩展R中包含列表的数据框

为什么我对圆周率图的蒙特卡罗估计是空的?

如何在R中使用混合GAM模型只对固定的影响因素进行适当的预测?

为R中的16组参数生成10000个样本的有效方法是什么?