首页 文章

用dplyr汇总多列? [重复]

提问于
浏览
126

这个问题在这里已有答案:

我在使用dplyr语法时遇到了一些麻烦 . 我有一个包含不同变量和一个分组变量的数据框 . 现在我想用R中的dplyr计算每个组中每列的平均值 .

df <- data.frame(
    a = sample(1:5, n, replace = TRUE), 
    b = sample(1:5, n, replace = TRUE), 
    c = sample(1:5, n, replace = TRUE), 
    d = sample(1:5, n, replace = TRUE), 
    grp = sample(1:3, n, replace = TRUE)
)
df %>% group_by(grp) %>% summarise(mean(a))

这给出了“grp”表示的每个组的“a”列的平均值 .

我的问题是:是否有可能同时获得每个组中每列的方法?或者我是否必须为每列重复 df %>% group_by(grp) %>% summarise(mean(a))

我想拥有的是类似的东西

df %>% group_by(grp) %>% summarise(mean(a:d)) # "mean(a:d)" does not work

5 回答

  • 212

    所有的例子都很棒,但我想再添加一个例子来说明如何使用"tidy"格式简化事情 . 现在,数据框采用"wide"格式,这意味着变量"a"到"d"以列表示 . 要获得"tidy"(或长)格式,可以使用 tidyr 包中的 gather() ,它将"a"到"d"列中的变量转换为行 . 然后使用 group_by()summarize() 函数来获取每个组的平均值 . 如果要以宽格式显示数据,只需再调用 spread() 函数即可 .

    library(tidyverse)
    
    # Create reproducible df
    set.seed(101)
    df <- tibble(a   = sample(1:5, 10, replace=T), 
                 b   = sample(1:5, 10, replace=T), 
                 c   = sample(1:5, 10, replace=T), 
                 d   = sample(1:5, 10, replace=T), 
                 grp = sample(1:3, 10, replace=T))
    
    # Convert to tidy format using gather
    df %>%
        gather(key = variable, value = value, a:d) %>%
        group_by(grp, variable) %>%
        summarize(mean = mean(value)) %>%
        spread(variable, mean)
    #> Source: local data frame [3 x 5]
    #> Groups: grp [3]
    #> 
    #>     grp        a     b        c        d
    #> * <int>    <dbl> <dbl>    <dbl>    <dbl>
    #> 1     1 3.000000   3.5 3.250000 3.250000
    #> 2     2 1.666667   4.0 4.666667 2.666667
    #> 3     3 3.333333   3.0 2.333333 2.333333
    
  • 32

    您可以简单地将更多参数传递给 summarise

    df %>% group_by(grp) %>% summarise(mean(a), mean(b), mean(c), mean(d))
    

    来源:本地数据框[3 x 5]

    grp  mean(a)  mean(b)  mean(c) mean(d)
    1   1 2.500000 3.500000 2.000000     3.0
    2   2 3.800000 3.200000 3.200000     2.8
    3   3 3.666667 3.333333 2.333333     3.0
    
  • 5

    为了完整性:使用dplyr v0.2 ddplycolwise 也会这样做:

    > ddply(df, .(grp), colwise(mean))
      grp        a    b        c        d
    1   1 4.333333 4.00 1.000000 2.000000
    2   2 2.000000 2.75 2.750000 2.750000
    3   3 3.000000 4.00 4.333333 3.666667
    

    但速度较慢,至少在这种情况下:

    > microbenchmark(ddply(df, .(grp), colwise(mean)), 
                      df %>% group_by(grp) %>% summarise_each(funs(mean)))
    Unit: milliseconds
                                                expr      min       lq     mean
                    ddply(df, .(grp), colwise(mean))     3.278002 3.331744 3.533835
     df %>% group_by(grp) %>% summarise_each(funs(mean)) 1.001789 1.031528 1.109337
    
       median       uq      max neval
     3.353633 3.378089 7.592209   100
     1.121954 1.133428 2.292216   100
    
  • 46

    dplyr 包为此目的包含 summarise_all

    df %>% group_by(grp) %>% summarise_all(funs(mean))
    #> Source: local data frame [3 x 5]
    #> 
    #>     grp        a        b        c        d
    #>   (int)    (dbl)    (dbl)    (dbl)    (dbl)
    #> 1     1 3.000000 2.666667 2.666667 3.333333
    #> 2     2 2.666667 2.666667 2.500000 2.833333
    #> 3     3 4.000000 1.000000 4.000000 3.000000
    

    如果只想汇总某些列,请使用 summarise_atsummarise_if 函数 .

    或者, purrrlyr 包提供相同的功能:

    df %>% slice_rows("grp") %>% dmap(mean)
    #> Source: local data frame [3 x 5]
    #> 
    #>     grp        a        b        c        d
    #>   (int)    (dbl)    (dbl)    (dbl)    (dbl)
    #> 1     1 3.000000 2.666667 2.666667 3.333333
    #> 2     2 2.666667 2.666667 2.500000 2.833333
    #> 3     3 4.000000 1.000000 4.000000 3.000000
    

    另外不要忘记 data.table

    setDT(df)[, lapply(.SD, mean), by = grp]
    #>    grp        a        b        c        d
    #> 1:   3 3.714286 3.714286 2.428571 2.428571
    #> 2:   1 1.000000 4.000000 5.000000 2.000000
    #> 3:   2 4.000000 4.500000 3.000000 3.000000
    

    我们试着比较一下性能 .

    library(dplyr)
    library(purrrlyr)
    library(data.table)
    library(benchr)
    n <- 10000
    df <- data.frame(
        a = sample(1:5, n, replace = TRUE), 
        b = sample(1:5, n, replace = TRUE), 
        c = sample(1:5, n, replace = TRUE), 
        d = sample(1:5, n, replace = TRUE), 
        grp = sample(1:3, n, replace = TRUE)
    )
    dt <- setDT(df)
    benchmark(
        dplyr = df %>% group_by(grp) %>% summarise_all(funs(mean)),
        purrrlyr = df %>% slice_rows("grp") %>% dmap(mean),
        data.table = dt[, lapply(.SD, mean), by = grp]
    )
    #> Benchmark summary:
    #> Time units : microseconds 
    #>        expr n.eval  min lw.qu median mean up.qu   max  total relative
    #>       dplyr    100 3490  3550   3710 3890  3780 15100 389000     6.98
    #>    purrrlyr    100 2540  2590   2680 2920  2860 12000 292000     5.04
    #>  data.table    100  459   500    531  563   571  1380  56300     1.00
    
  • 3

    我们可以在 dplyr 0.7.4 上使用 summarize_atsummarize_allsummarize_if 进行汇总 . 我们可以使用 varsfuns 参数设置多个列和函数,如下面的代码所示 . funs公式的左侧被指定为汇总变量的后缀 . 在 dplyr 0.7.4 中, summarise_each (和 mutate_each )已被弃用,因此我们无法使用这些函数 .

    options(scipen = 100, dplyr.width = Inf, dplyr.print_max = Inf)
    
    library(dplyr)
    packageVersion("dplyr")
    # [1] ‘0.7.4’
    
    set.seed(123)
    df <- data_frame(
      a = sample(1:5, 10, replace=T), 
      b = sample(1:5, 10, replace=T), 
      c = sample(1:5, 10, replace=T), 
      d = sample(1:5, 10, replace=T), 
      grp = as.character(sample(1:3, 10, replace=T)) # For convenience, specify character type
    )
    
    df %>% group_by(grp) %>% 
      summarise_each(.vars = letters[1:4],
                     .funs = c(mean="mean"))
    # `summarise_each()` is deprecated.
    # Use `summarise_all()`, `summarise_at()` or `summarise_if()` instead.
    # To map `funs` over a selection of variables, use `summarise_at()`
    # Error: Strings must match column names. Unknown columns: mean
    

    您应该更改为以下代码 . 以下代码都具有相同的结果 .

    # summarise_at
    df %>% group_by(grp) %>% 
      summarise_at(.vars = letters[1:4],
                   .funs = c(mean="mean"))
    
    df %>% group_by(grp) %>% 
      summarise_at(.vars = names(.)[1:4],
                   .funs = c(mean="mean"))
    
    df %>% group_by(grp) %>% 
      summarise_at(.vars = vars(a,b,c,d),
                   .funs = c(mean="mean"))
    
    # summarise_all
    df %>% group_by(grp) %>% 
      summarise_all(.funs = c(mean="mean"))
    
    # summarise_if
    df %>% group_by(grp) %>% 
      summarise_if(.predicate = function(x) is.numeric(x),
                   .funs = funs(mean="mean"))
    # A tibble: 3 x 5
    # grp a_mean b_mean c_mean d_mean
    # <chr>  <dbl>  <dbl>  <dbl>  <dbl>
    # 1     1   2.80   3.00    3.6   3.00
    # 2     2   4.25   2.75    4.0   3.75
    # 3     3   3.00   5.00    1.0   2.00
    

    您还可以拥有多种功能 .

    df %>% group_by(grp) %>% 
      summarise_at(.vars = letters[1:2],
                   .funs = c(Mean="mean", Sd="sd"))
    # A tibble: 3 x 5
    # grp a_Mean b_Mean      a_Sd     b_Sd
    # <chr>  <dbl>  <dbl>     <dbl>    <dbl>
    # 1     1   2.80   3.00 1.4832397 1.870829
    # 2     2   4.25   2.75 0.9574271 1.258306
    # 3     3   3.00   5.00        NA       NA
    

相关问题