Podsumowanie wielu kolumn za pomocą dplyr? [duplikat]
To pytanie ma już odpowiedź tutaj:
- agregacja / podsumowanie wielu zmiennych w grupie (np. suma, średnia) 5 odpowiedzi
- Czy dplyr może podsumować kilka zmiennych bez wymieniania każdej z nich? [duplicate] 2 odpowiedzi
Trochę zmagam się ze składnią dplyr. Mam ramkę danych z różnymi zmiennymi i jedną zmienną grupującą. Teraz chcę obliczyć średnią dla każdej kolumny w każdej grupie, używając dplyr w 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))
To daje mi średnią dla kolumny " a "dla każdej grupy wskazanej przez"grp".
Moje pytanie brzmi: czy możliwe jest uzyskanie środków dla każdej kolumny w każdej grupie na raz? Czy muszę powtarzać df %>% group_by(grp) %>% summarise(mean(a))
dla każdej kolumny?
To, co chciałbym mieć, to coś jak
df %>% group_by(grp) %>% summarise(mean(a:d)) # "mean(a:d)" does not work
5 answers
Pakiet dplyr
zawiera summarise_all
do tego celu:
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
Jeśli chcesz podsumować tylko niektóre kolumny, użyj funkcji summarise_at
lub summarise_if
.
Alternatywnie, pakiet purrrlyr
zapewnia tę samą funkcjonalność:
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
Również nie zapomnij o 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
Spróbujmy porównać wydajność.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 03:06:09
Możemy podsumować używając summarize_at
, summarize_all
i summarize_if
na dplyr 0.7.4
. Możemy ustawić wiele kolumn i funkcji za pomocą vars
i funs
argument jak poniżej kodu. Lewa strona wzoru funsa jest przypisana do sufiksu sumowanych var. W dplyr 0.7.4
, summarise_each
(and mutate_each
) jest już przestarzały, więc nie możemy korzystać z tych funkcji.
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
Należy zmienić na następujący kod. Poniższe kody mają ten sam wynik.
# 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
Możesz także mieć wiele funkcje.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-18 09:52:18
Możesz po prostu przekazać więcej argumentów summarise
:
df %>% group_by(grp) %>% summarise(mean(a), mean(b), mean(c), mean(d))
Źródło: lokalna ramka danych [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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-21 11:02:18
Dla kompletności: z dplyr v0. 2 ddply
z colwise
zrobi to również:
> 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
Ale jest wolniej, przynajmniej w tym przypadku:
> 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-01 23:06:25
Wszystkie przykłady są świetne, ale pomyślałem, że dodam jeszcze jeden, aby pokazać, jak Praca w "uporządkowanym" formacie upraszcza rzeczy. Obecnie ramka danych jest w formacie "wide", co oznacza, że zmienne od " A " do " d " są reprezentowane w kolumnach. Aby przejść do formatu" tidy "(lub długiego), możesz użyć gather()
z pakietu tidyr
, który przenosi zmienne w kolumnach " a "przez" d " do wierszy. Następnie używasz funkcji group_by()
i summarize()
, Aby uzyskać średnią z każdej grupy. Jeśli chcesz zaprezentować dane w szerokim sformatować, wystarczy podłączyć dodatkowe wywołanie do funkcji 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-06 21:37:46