Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/76.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
data.table vs dplyr:一个能做好某件事,另一个能';还是做得不好? 概述_R_Data.table_Dplyr - Fatal编程技术网

data.table vs dplyr:一个能做好某件事,另一个能';还是做得不好? 概述

data.table vs dplyr:一个能做好某件事,另一个能';还是做得不好? 概述,r,data.table,dplyr,R,Data.table,Dplyr,我比较熟悉data.table,而不是dplyr。我已经通读了一些突然出现的例子,到目前为止,我的结论是: 数据。表和dplyr在速度上具有可比性,但有许多(即>10-100K)组的情况除外,以及在某些其他情况下(见下文基准测试) dplyr具有更易访问的语法 dplyr摘要(或将摘要)潜在的数据库交互 存在一些细微的功能差异(请参见下面的“示例/用法”) 在我心目中2。没有太大的影响力,因为我对它非常熟悉data.table,尽管我知道,对于两个领域的新手来说,它将是一个重要因素。我想避免关于

我比较熟悉
data.table
,而不是
dplyr
。我已经通读了一些突然出现的例子,到目前为止,我的结论是:

  • 数据。表
    dplyr
    在速度上具有可比性,但有许多(即>10-100K)组的情况除外,以及在某些其他情况下(见下文基准测试)
  • dplyr
    具有更易访问的语法
  • dplyr
    摘要(或将摘要)潜在的数据库交互
  • 存在一些细微的功能差异(请参见下面的“示例/用法”)
  • 在我心目中2。没有太大的影响力,因为我对它非常熟悉
    data.table
    ,尽管我知道,对于两个领域的新手来说,它将是一个重要因素。我想避免关于哪个更直观的争论,因为这与我从熟悉
    data.table
    的人的角度提出的具体问题无关。我还想避免讨论“更直观”如何导致更快的分析(当然是真的,但再一次,这不是我最感兴趣的)

    问题: 我想知道的是:

  • 对于熟悉软件包的人来说,是否有更容易使用一个或另一个软件包进行编码的分析任务(即,所需击键与所需深奥程度的某种组合,其中每种击键次数越少越好)
  • 是否存在在一个包中比在另一个包中更有效地执行分析任务(即超过2倍)
  • 其中一个问题让我更仔细地思考了一下,因为在那之前,我认为
    dplyr
    提供的功能远远超出了我在
    data.table
    中所能提供的功能。以下是
    dplyr
    解决方案(数据在Q末尾):

    这比我尝试的
    data.table
    解决方案要好得多。也就是说,很好的
    数据。table
    解决方案也很好(感谢Jean-Robert,Arun,请注意,在这里我倾向于使用单一语句,而不是严格意义上的最佳解决方案):

    后者的语法可能看起来非常深奥,但如果您习惯了
    data.table
    (即不使用一些更深奥的技巧),它实际上非常简单

    理想情况下,我想看到的是一些很好的例子,如
    dplyr
    数据。table
    方法更简洁或性能更好

    例子 用法
    • dplyr
      不允许返回任意行数的分组操作(从,注意:这看起来将在中实现,@初学者在回答@eddi的问题时显示了使用
      do
      的潜在解决方法)
    • data.table
      支持(感谢@dholstius)以及
    • data.table
      内部优化了
      DT[col==value]
      DT[col%in%values]
      形式的表达式,通过使用二进制搜索的自动索引,同时使用相同的基本R语法,提高了速度。了解更多细节和一个小基准
    • dplyr
      提供标准的函数评估版本(例如,
      regroup
      summary\u each
      ),可以简化
      dplyr的编程使用(注意,
      数据的编程使用。表
      绝对是可能的,只是需要仔细考虑、替换/引用等,至少据我所知)
    基准
    • 我运行了并发现这两个包在“split-apply-combine”风格的分析中是可比较的,除非有非常多的组(>100K),此时
      数据。table
      变得更快
    • @Arun运行了一些,显示
      数据。随着组数的增加,
      dplyr
      表的伸缩性比
      dplyr更好(更新了包中的最新增强功能和最新版本的R)。此外,尝试获取数据时的基准测试速度比
      表快6倍
    • (未验证)具有
      数据。表
      在较大版本的组/应用/排序上快75%,而
      dplyr
      在较小版本上快40%(,感谢danas)
    • 马特是《数据表》的主要作者
    • 具有
      数据。表格的速度大约快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))
    
    dat直接回答问题标题。。。
    
    dplyr
    肯定做了
    data.table
    做不到的事情。 你的观点是#3

    dplyr抽象(或将抽象)潜在的数据库交互

    是对您自己问题的直接回答,但没有提升到足够高的级别。
    dplyr
    确实是一个可扩展的前端,可扩展到多个数据存储机制,其中as
    data.table
    是对单个数据存储机制的扩展

    dplyr
    视为后端不可知界面,所有目标都使用相同的语法,您可以在其中随意扩展目标和处理程序。
    数据。从
    dplyr
    的角度来看,表是其中一个目标

    您永远不会(我希望)看到有一天
    数据。table
    试图转换您的查询以创建SQL语句,这些SQL语句可以在磁盘或网络数据存储中运行

    dplyr
    可能会处理
    数据。table
    不会也可能不会处理。 基于内存工作的设计,
    data.table
    将自身扩展到查询的并行处理可能比
    dplyr
    困难得多


    在回答体内问题时。。。 用法 对于熟悉软件包的人来说,是否有更容易用一个或另一个软件包进行编码的分析任务(i
    setDT(dat)[,
      .SD[job != "Boss" | year == min(year)][, cumjob := cumsum(job2)], 
      by=list(id, job)
    ]
    
    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))
    
     # sub-assign by reference, updates 'y' in-place
     DT[x >= 1L, y := NA]
    
     # copies the entire 'y' column
     ans <- DF %>% mutate(y = replace(y, which(x >= 1L), NA))
    
     foo <- function(DT) {
         DT = shallow(DT)          ## shallow copy DT
         DT[, newcol := 1L]        ## does not affect the original DT 
         DT[x > 2L, newcol := 2L]  ## no need to copy (internally), as this column exists only in shallow copied DT
         DT[x > 2L, x := 3L]       ## have to copy (like base R / dplyr does always); otherwise original DT will 
                                   ## also get modified.
     }
    
     bar <- function(DT) {
         DT[, newcol := 1L]        ## old behaviour, original DT gets updated by reference
         DT[x > 2L, x := 3L]       ## old behaviour, update column x in original DT.
     }
    
     DT1 = data.table(x=c(1,1,1,1,2,2,2,2), y=c("a", "a", "b", "b"), z=1:8, key=c("x", "y"))
     #    x y z
     # 1: 1 a 1
     # 2: 1 a 2
     # 3: 1 b 3
     # 4: 1 b 4
     # 5: 2 a 5
     # 6: 2 a 6
     # 7: 2 b 7
     # 8: 2 b 8
     DT2 = data.table(x=1:2, y=c("a", "b"), mul=4:3, key=c("x", "y"))
     #    x y mul
     # 1: 1 a   4
     # 2: 2 b   3
    
     DT1[DT2, col := i.mul]
    
    DT = data.table(x=1:10, y=11:20, z=rep(1:2, each=5))
    DF = as.data.frame(DT)
    
     # case (a)
     DT[, sum(y), by = z]                       ## data.table syntax
     DF %>% group_by(z) %>% summarise(sum(y)) ## dplyr syntax
     DT[, y := cumsum(y), by = z]
     ans <- DF %>% group_by(z) %>% mutate(y = cumsum(y))
    
     # case (b)
     DT[x > 2, sum(y), by = z]
     DF %>% filter(x>2) %>% group_by(z) %>% summarise(sum(y))
     DT[x > 2, y := cumsum(y), by = z]
     ans <- DF %>% group_by(z) %>% mutate(y = replace(y, which(x > 2), cumsum(y)))
    
     # case (c)
     DT[, if(any(x > 5L)) y[1L]-y[2L] else y[2L], by = z]
     DF %>% group_by(z) %>% summarise(if (any(x > 5L)) y[1L] - y[2L] else y[2L])
     DT[, if(any(x > 5L)) y[1L] - y[2L], by = z]
     DF %>% group_by(z) %>% filter(any(x > 5L)) %>% summarise(y[1L] - y[2L])
    
     # case (a)
     DT[, lapply(.SD, sum), by = z]                     ## data.table syntax
     DF %>% group_by(z) %>% summarise_each(funs(sum)) ## dplyr syntax
     DT[, (cols) := lapply(.SD, sum), by = z]
     ans <- DF %>% group_by(z) %>% mutate_each(funs(sum))
    
     # case (b)
     DT[, c(lapply(.SD, sum), lapply(.SD, mean)), by = z]
     DF %>% group_by(z) %>% summarise_each(funs(sum, mean))
    
     # case (c)
     DT[, c(.N, lapply(.SD, sum)), by = z]     
     DF %>% group_by(z) %>% summarise_each(funs(n(), mean))
    
     setkey(DT1, x, y)
    
     # 1. normal join
     DT1[DT2]            ## data.table syntax
     left_join(DT2, DT1) ## dplyr syntax
    
     # 2. select columns while join    
     DT1[DT2, .(z, i.mul)]
     left_join(select(DT2, x, y, mul), select(DT1, x, y, z))
    
     # 3. aggregate while join
     DT1[DT2, .(sum(z) * i.mul), by = .EACHI]
     DF1 %>% group_by(x, y) %>% summarise(z = sum(z)) %>% 
         inner_join(DF2) %>% mutate(z = z*mul) %>% select(-mul)
    
     # 4. update while join
     DT1[DT2, z := cumsum(z) * i.mul, by = .EACHI]
     ??
    
     # 5. rolling join
     DT1[DT2, roll = -Inf]
     ??
    
     # 6. other arguments to control output
     DT1[DT2, mult = "first"]
     ??
    
     DT[, list(x[1], y[1]), by = z]                 ## data.table syntax
     DF %>% group_by(z) %>% summarise(x[1], y[1]) ## dplyr syntax
     DT[, list(x[1:2], y[1]), by = z]
     DF %>% group_by(z) %>% do(data.frame(.$x[1:2], .$y[1]))
    
     DT[, quantile(x, 0.25), by = z]
     DF %>% group_by(z) %>% summarise(quantile(x, 0.25))
     DT[, quantile(x, c(0.25, 0.75)), by = z]
     DF %>% group_by(z) %>% do(data.frame(quantile(.$x, c(0.25, 0.75))))
    
     DT[, as.list(summary(x)), by = z]
     DF %>% group_by(z) %>% do(data.frame(as.list(summary(.$x))))
    
    diamonds %>%
      filter(cut != "Fair") %>%
      group_by(cut) %>%
      summarize(
        AvgPrice = mean(price),
        MedianPrice = as.numeric(median(price)),
        Count = n()
      ) %>%
      arrange(desc(Count))
    
    diamondsDT <- data.table(diamonds)
    diamondsDT[
      cut != "Fair", 
      .(AvgPrice = mean(price),
        MedianPrice = as.numeric(median(price)),
        Count = .N
      ), 
      by = cut
    ][ 
      order(-Count) 
    ]
    
    diamonds %>% 
      data.table() %>% 
      .[cut != "Fair", 
        .(AvgPrice = mean(price),
          MedianPrice = as.numeric(median(price)),
          Count = .N
        ), 
        by = cut
      ] %>% 
      .[order(-Count)]
    
    new_table <- mtcars2 %>% 
      lazy_dt() %>%
      filter(wt < 5) %>% 
      mutate(l100k = 235.21 / mpg) %>% # liters / 100 km
      group_by(cyl) %>% 
      summarise(l100k = mean(l100k))
    
      new_table
    
    #> Source: local data table [?? x 2]
    #> Call:   `_DT1`[wt < 5][, `:=`(l100k = 235.21/mpg)][, .(l100k = mean(l100k)), 
    #>     keyby = .(cyl)]
    #> 
    #>     cyl l100k
    #>   <dbl> <dbl>
    #> 1     4  9.05
    #> 2     6 12.0 
    #> 3     8 14.9 
    #> 
    #> # Use as.data.table()/as.data.frame()/as_tibble() to access results