【问题标题】:What is the dplyr equivalent of plyr::ldply(tapply) in R?什么是 R 中 plyr::ldply(tapply) 的 dplyr 等价物?
【发布时间】:2015-08-16 07:56:10
【问题描述】:

最终,我试图实现类似于以下内容,但利用dplyr 而不是plyr

library(dplyr)  
probs = seq(0, 1, 0.1)

plyr::ldply(tapply(mtcars$mpg, 
                   mtcars$cyl, 
                   function(x) { quantile(x, probs = probs) }))

#   .id   0%   10%   20%   30%   40%  50%   60%   70%   80%   90% 100%
# 1   4 21.4 21.50 22.80 22.80 24.40 26.0 27.30 30.40 30.40 32.40 33.9
# 2   6 17.8 17.98 18.32 18.98 19.40 19.7 20.48 21.00 21.00 21.16 21.4
# 3   8 10.4 11.27 13.90 14.66 15.04 15.2 15.44 15.86 16.76 18.28 19.2

我能想到的最好的dplyr 等价物是这样的:

library(tidyr)
probs = seq(0, 1, 0.1)

mtcars %>%
  group_by(cyl) %>%
  do(data.frame(prob = probs, stat = quantile(.$mpg, probs = probs))) %>%
  spread(prob, stat)

#   cyl    0   0.1   0.2   0.3   0.4  0.5   0.6   0.7   0.8   0.9    1
# 1   4 21.4 21.50 22.80 22.80 24.40 26.0 27.30 30.40 30.40 32.40 33.9
# 2   6 17.8 17.98 18.32 18.98 19.40 19.7 20.48 21.00 21.00 21.16 21.4
# 3   8 10.4 11.27 13.90 14.66 15.04 15.2 15.44 15.86 16.76 18.28 19.2

请注意,我还需要使用tidyr::spread。此外,请注意,我丢失了列标题的 % 格式,以便将第一列中的 .id 替换为 cyl

问题:

  1. 是否有更好的基于dplyr 的方法来完成此任务 tapply %>% ldply链?
  2. 有没有一种方法可以兼顾两者 没有跳过太多圈的世界?也就是说,获取% 第一列的格式和正确的 cyl 列名称?

【问题讨论】:

    标签: r plyr dplyr tidyr


    【解决方案1】:

    使用dplyr

    library(dplyr)
    mtcars %>% 
       group_by(cyl) %>% 
       do(data.frame(as.list(quantile(.$mpg,probs=probs)), check.names=FALSE))
    #  cyl   0%   10%   20%   30%   40%  50%   60%   70%   80%   90% 100%
    #1   4 21.4 21.50 22.80 22.80 24.40 26.0 27.30 30.40 30.40 32.40 33.9
    #2   6 17.8 17.98 18.32 18.98 19.40 19.7 20.48 21.00 21.00 21.16 21.4
    #3   8 10.4 11.27 13.90 14.66 15.04 15.2 15.44 15.86 16.76 18.28 19.2
    

    或者使用data.table的选项

    library(data.table)
    as.data.table(mtcars)[, as.list(quantile(mpg, probs=probs)) , cyl]
    #   cyl   0%   10%   20%   30%   40%  50%   60%   70%   80%   90% 100%
    #1:   6 17.8 17.98 18.32 18.98 19.40 19.7 20.48 21.00 21.00 21.16 21.4
    #2:   4 21.4 21.50 22.80 22.80 24.40 26.0 27.30 30.40 30.40 32.40 33.9
    #3:   8 10.4 11.27 13.90 14.66 15.04 15.2 15.44 15.86 16.76 18.28 19.2
    

    【讨论】:

    • 想解释一下check.names = FALSE?
    • @JasonAlzkains 这是data.frame 中的一个参数,默认选项是check.names=TRUE。因此,如果列名以非数字值开头,则会将X 附加到它上面。相关代码为` if (check.names) vnames
    【解决方案2】:

    @akrun 的版本很好,但我会在do 语句中使用data_frame_

    mtcars %>% 
      group_by(cyl) %>% 
      do(data_frame_(quantile(.$mpg, probs = probs)))
    ## Source: local data frame [3 x 12]
    ## Groups: cyl
    ## 
    ##   cyl   0%   10%   20%   30%   40%  50%   60%   70%   80%   90% 100%
    ## 1   4 21.4 21.50 22.80 22.80 24.40 26.0 27.30 30.40 30.40 32.40 33.9
    ## 2   6 17.8 17.98 18.32 18.98 19.40 19.7 20.48 21.00 21.00 21.16 21.4
    ## 3   8 10.4 11.27 13.90 14.66 15.04 15.2 15.44 15.86 16.76 18.28 19.2
    

    在进一步调查其工作原理后,看起来data_frame_dplyr 中使用的常用 SE 逻辑不同。 data_frame_ 只接受一个参数 columns 并且确实需要一个 lazy_dots 参数。

    如果它得到一个向量,它就可以工作,因为对单个参数的惰性求值是有效的。所以在这样的向量上使用data_frame_ 这个特性实际上可能是一个错误。

    【讨论】:

    • 不知道data_frame_ 以紧凑的方式工作。好资料!
    • 有没有办法使用data_frame_() 生成长格式的输出呢?
    • @Arun:您可以使用lazy_dots,但这似乎有点过于复杂:data_frame_(lazyeval::lazy_dots(quantile(.$mpg, probs = probs)))。不知道更简单的解决方案。当然这相当于data_frame(quantile(.$mpg, probs = probs))
    • @shadow - 非常有趣,不确定我是否完全理解为什么这行得通,我猜其他人会从你的回答中的解释中受益。
    • @JasonAizkalns +1。阴影,在我看来 data_frame()data_frame_() 应该产生相同的结果..(因为一个是 SE 而另一个是 NSE)?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 2021-06-19
    • 2011-01-07
    • 1970-01-01
    • 2020-11-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多