用dplyr总结多个列?
我用dplyr语法挣扎了一下。 我有一个数据框与不同的variables和一个分组variables。 现在我想计算每个组内每列的平均值,在R中使用dplyr。
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=sample(1:3, 10, replace=T)) 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
dplyr
0.2包含了这个目标的dplyr
:
df %>% group_by(grp) %>% summarise_each(funs(mean)) #> Source: local data frame [3 x 5] #> #> grp abcd #> (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
或者, purrr
包提供了相同的function:
df %>% slice_rows("grp") %>% dmap(mean) #> Source: local data frame [3 x 5] #> #> grp abcd #> (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 abcd #> 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
你可以简单地传递更多的参数来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
我们可以通过在dplyr 0.7.3
上使用summarize_at
, summarize_all
和summarize_if来进行summarize_at
。 我们可以使用vars
和funs
参数作为下面的代码来设置多个列和函数。 funs公式的左边被分配给汇总variables的后缀。 在dplyr 0.7.3
, dplyr 0.7.3
(和mutate_each
)已经被弃用了,所以我们不能使用这些函数。
options(scipen = 100, dplyr.width = Inf, dplyr.print_max = Inf) library(dplyr) packageVersion("dplyr") # [1] '0.7.3' 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
你也可以有多个function。
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
为了完整性:与dplyr v0.2 ddply
与colwise
也将这样做:
> ddply(df, .(grp), colwise(mean)) grp abcd 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
但速度较慢,至less在这种情况下:
> 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
所有的例子都很好,但是我想再补充一点来说明如何用“整齐”的格式来简化事情。 数据框现在是“宽”格式,这意味着variables“a”到“d”以列表示。 要获得一个“整齐”(或长)格式,可以使用tidyr
包中的gather()
,将列“a”到“d”中的variables转换为行。 然后使用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 abcd #> * <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