Résumé de plusieurs colonnes avec dplyr? [dupliquer]

cette question a déjà une réponse ici:

  • agréger / résumer plusieurs variables par groupe (par exemple somme, moyenne) 5 réponses
  • Peut dplyr résumer sur plusieurs variables sans faire une liste de chacun? [duplicate] 2 réponses

j'ai un peu de mal avec la syntaxe dplyr. J'ai une base de données avec différentes variables et une variable de regroupement. Maintenant je veux calculer la moyenne pour chaque colonne dans chaque groupe, en utilisant dplyr dans R.

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))

me donne la moyenne pour la colonne" a "pour chaque groupe indiqué par"grp".

Ma question est: est-il possible d'obtenir les moyens pour chaque colonne dans chaque groupe à la fois? Ou dois-je répéter df %>% group_by(grp) %>% summarise(mean(a)) pour chaque colonne?

Ce que j'aimerais avoir, c'est quelque chose comme

df %>% group_by(grp) %>% summarise(mean(a:d)) # "mean(a:d)" does not work
121
demandé sur Artem Klevtsov 2014-02-08 14:27:10

5 réponses

le paquet dplyr contient summarise_all à cet effet:

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

si vous voulez résumer seulement certaines colonnes, utilisez les fonctions summarise_at ou summarise_if .

alternativement, le paquet purrrlyr offre la même fonctionnalité:

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

N'oubliez pas non plus 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

essayons de comparer les performances.

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
204
répondu Artem Klevtsov 2018-02-12 03:06:09

nous pouvons résumer en utilisant summarize_at , summarize_all et summarize_if sur dplyr 0.7.4 . Nous pouvons définir les colonnes et les fonctions multiples en utilisant l'argument vars et funs comme code ci-dessous. Le côté gauche de la formule de funs est assigné au suffixe des var résumées. Dans le dplyr 0.7.4 , summarise_each (et mutate_each ) est déjà déprécié, donc nous ne pouvons pas utiliser ces fonctions.

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

vous devez changer le code suivant. Le codes suivants ont tous le même résultat.

# 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

vous pouvez également avoir plusieurs fonctions.

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
43
répondu Keiku 2017-11-18 09:52:18

vous pouvez simplement passer plus d'arguments à summarise :

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

Source: base de données locale [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
32
répondu Paul Hiemstra 2016-01-21 11:02:18

complet: avec dplyr v0.2 ddply avec colwise fera également:

> 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

mais il est plus lent, au moins dans ce cas:

> 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
5
répondu Steven Matz 2015-12-01 23:06:25

tous les exemples sont géniaux, mais je me suis dit que j'en ajouterais un de plus pour montrer comment travailler dans un format "ordonné" simplifie les choses. À l'heure actuelle, la base de données est dans un format "large", ce qui signifie que les variables "a" à "d" sont représentées dans les colonnes. Pour obtenir un format" ordonné "(ou long), vous pouvez utiliser gather() du paquet tidyr qui déplace les variables dans les colonnes" a "à" d " en lignes. Ensuite, vous utilisez les fonctions group_by() et summarize() pour obtenir la moyenne de chaque groupe. Si vous vous souhaitez présenter les données dans un format large, il suffit de cliquer sur un appel supplémentaire à la fonction 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
3
répondu Matt Dancho 2017-03-06 21:37:46