Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
dplyr on data.table,我真的在使用data.table吗?_R_Data.table_Dplyr - Fatal编程技术网

dplyr on data.table,我真的在使用data.table吗?

dplyr on data.table,我真的在使用data.table吗?,r,data.table,dplyr,R,Data.table,Dplyr,如果我在数据表的基础上使用dplyr语法,那么在仍然使用dplyr语法的情况下,我是否能获得数据表的所有速度优势?换句话说,如果我用dplyr语法查询数据表,我是否会误用它?或者我需要使用纯数据表语法来利用它的所有功能 提前谢谢你的建议。代码示例: library(data.table) library(dplyr) diamondsDT <- data.table(ggplot2::diamonds) setkey(diamondsDT, cut) diamondsDT %>

如果我在数据表的基础上使用dplyr语法,那么在仍然使用dplyr语法的情况下,我是否能获得数据表的所有速度优势?换句话说,如果我用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))
这是我提出的数据表等价性。不确定是否符合DT良好实践。但我想知道在幕后,代码是否真的比dplyr语法更有效:

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

library(rbenchmark)
library(dplyr)
library(data.table)

benchmark(
dplyr = diamondsDT %>%
    filter(cut != "Fair") %>%
    group_by(cut) %>%
    summarize(AvgPrice = mean(price),
                 MedianPrice = as.numeric(median(price)),
                 Count = n()) %>%
    arrange(desc(Count)),
data.table = diamondsDT[cut != "Fair", 
                        list(AvgPrice = mean(price),
                             MedianPrice = as.numeric(median(price)),
                             Count = .N), by = cut][order(-Count)])[1:4]
在这个问题上,data.table似乎比使用data.table的dplyr快2.4倍:

        test replications elapsed relative
2 data.table          100    2.39    1.000
1      dplyr          100    5.77    2.414

根据多聚酶的评论进行修订。

回答您的问题:

  • 是的,您正在使用
    数据。表
  • 但是没有使用纯
    data.table
    语法时那么有效
在许多情况下,对于那些需要
dplyr
语法的人来说,这将是一个可接受的折衷方案,尽管对于普通数据帧,它可能比
dplyr

一个重要因素似乎是分组时默认情况下,
dplyr
将复制
数据表。考虑(使用微基准):

过滤速度相当,但分组速度不一样。我相信罪魁祸首是
dplyr:::grouped\u dt
:

if (copy) {
    data <- data.table::copy(data)
}

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

涉及
i
(==
filter()
slice()
的操作,在dplyr中) 假设
DT
有10列。考虑这些DATA表表达式:

DT[a > 1, .N]                    ## --- (1)
DT[a > 1, mean(b), by=.(c, d)]   ## --- (2)
(1) 给出
DT
中的行数,其中列
a>1
。(2) 对于
i
中的同一表达式,返回按
c,d
分组的
mean(b)
,与(1)相同

常用的
dplyr
表达式为:

DT %>% filter(a > 1) %>% summarise(n())                        ## --- (3) 
DT %>% filter(a > 1) %>% group_by(c, d) %>% summarise(mean(b)) ## --- (4)
显然,数据表代码较短。此外,它们还具有更高的内存效率1。为什么?因为在(3)和(4)中,
filter()
首先返回所有10列的行,在(3)中,我们只需要行数,在(4)中,我们只需要列
b、c、d
来进行后续操作。要克服这一点,我们必须
select()
columns apriori:

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表达式(来自同一个函数调用),并意识到不需要(1)中的任何列。计算
    i
    中的表达式,
    .N
    只是给出行数的逻辑向量的总和;整个子集从未实现。在(2)中,只有列
    b、c、d
    在子集中具体化,其他列被忽略

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

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

通过引用进行子分配 dplyr永远不会通过引用进行更新。这是两个软件包之间的另一个巨大(哲学)差异

例如,在data.table中,您可以执行以下操作:

DT[a %in% some_vals, a := NA]
它仅在满足条件的行上通过引用更新列
a
。此时,dplyr deep在内部复制整个data.table以添加新列@布罗迪格在回答中已经提到了这一点

但在实现时,深度副本可以被浅层副本替换。也相关:。请注意,您修改的列将始终被复制(因此速度较慢/内存效率较低)。无法通过引用更新列

其他功能
  • 在data.table中,您可以在连接时进行聚合,这更易于理解,而且内存效率也更高,因为中间连接结果从未实现。请查看示例。使用dplyr的data.table/data.frame语法(目前?)无法做到这一点

  • dplyr的语法也不支持data.table的功能

  • 我们最近在data.table中实现了重叠连接,以在区间范围()上进行连接,这是目前一个单独的函数
    foverlaps()
    ,因此可以与管道操作符一起使用(magrittr/pipeR?-我从未尝试过)

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

  • 自1.9.4以来,data.table使用辅助键实现自动索引,用于基于常规R语法的快速二进制搜索子集。例如:
    DT[x==1]
    DT[x%部分值]
    将在第一次运行时自动创建索引,然后使用二进制搜索将索引用于从同一列到快速子集的连续子集。此功能将继续发展。请查看此功能的简要概述

    从data.tables的
    filter()
    实现方式来看,它没有利用此功能

  • 一个dplyr f
    DT %>% filter(a > 1) %>% summarise(n())                        ## --- (3) 
    DT %>% filter(a > 1) %>% group_by(c, d) %>% summarise(mean(b)) ## --- (4)
    
    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)
    
    DT[a %in% some_vals, a := NA]