提问人:broccoli 提问时间:8/22/2012 最后编辑:Gregor Thomasbroccoli 更新时间:11/29/2022 访问量:118288
在一次调用中按组对多个变量应用多个汇总函数(总和、平均值等)
Apply several summary functions (sum, mean, etc.) on several variables by group in one call
问:
我有以下数据框
x <- read.table(text = " id1 id2 val1 val2
1 a x 1 9
2 a x 2 4
3 a y 3 5
4 a y 4 9
5 b x 1 7
6 b y 4 4
7 b x 3 9
8 b y 2 8", header = TRUE)
我想计算按 id1 和 id2 分组的 val1 和 val2 的平均值,并同时计算每个 id1-id2 组合的行数。我可以单独执行每个计算:
# calculate mean
aggregate(. ~ id1 + id2, data = x, FUN = mean)
# count rows
aggregate(. ~ id1 + id2, data = x, FUN = length)
为了在一次调用中同时进行两个计算,我尝试了
do.call("rbind", aggregate(. ~ id1 + id2, data = x, FUN = function(x) data.frame(m = mean(x), n = length(x))))
但是,我收到一个乱码输出以及警告:
# m n
# id1 1 2
# id2 1 1
# 1.5 2
# 2 2
# 3.5 2
# 3 2
# 6.5 2
# 8 2
# 7 2
# 6 2
# Warning message:
# In rbind(id1 = c(1L, 2L, 1L, 2L), id2 = c(1L, 1L, 2L, 2L), val1 = list( :
# number of columns of result is not a multiple of vector length (arg 1)
我可以使用 plyr 包,但我的数据集非常大,当数据集的大小增长时,plyr 非常慢(几乎无法使用)。
如何使用或其他函数在一次调用中执行多个计算?aggregate
答:
也许你想合并?
x.mean <- aggregate(. ~ id1+id2, p, mean)
x.len <- aggregate(. ~ id1+id2, p, length)
merge(x.mean, x.len, by = c("id1", "id2"))
id1 id2 val1.x val2.x val1.y val2.y
1 a x 1.5 6.5 2 2
2 a y 3.5 7.0 2 2
3 b x 2.0 8.0 2 2
4 b y 3.0 6.0 2 2
您可以在一个步骤中完成所有操作并获得适当的标签:
> aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )
# id1 id2 val1.mn val1.n val2.mn val2.n
# 1 a x 1.5 2.0 6.5 2.0
# 2 b x 2.0 2.0 8.0 2.0
# 3 a y 3.5 2.0 7.0 2.0
# 4 b y 3.0 2.0 6.0 2.0
这将创建一个包含两个 id 列和两个矩阵列的 DataFrame:
str( aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) )
'data.frame': 4 obs. of 4 variables:
$ id1 : Factor w/ 2 levels "a","b": 1 2 1 2
$ id2 : Factor w/ 2 levels "x","y": 1 1 2 2
$ val1: num [1:4, 1:2] 1.5 2 3.5 3 2 2 2 2
..- attr(*, "dimnames")=List of 2
.. ..$ : NULL
.. ..$ : chr "mn" "n"
$ val2: num [1:4, 1:2] 6.5 8 7 6 2 2 2 2
..- attr(*, "dimnames")=List of 2
.. ..$ : NULL
.. ..$ : chr "mn" "n"
正如下面的 @lord.garbage 所指出的,这可以通过以下命令将其转换为具有“简单”列的 DataFramedo.call(data.frame, ...)
str( do.call(data.frame, aggregate(. ~ id1+id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) ) )
)
'data.frame': 4 obs. of 6 variables:
$ id1 : Factor w/ 2 levels "a","b": 1 2 1 2
$ id2 : Factor w/ 2 levels "x","y": 1 1 2 2
$ val1.mn: num 1.5 2 3.5 3
$ val1.n : num 2 2 2 2
$ val2.mn: num 6.5 8 7 6
$ val2.n : num 2 2 2 2
以下是 LHS 上多个变量的语法:
aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )
评论
d$val1[ , ""mn"]
str
agg <- aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x)))
agg_df <- do.call(data.frame, agg)
您可以添加一列,与 聚合,然后缩减以获取:count
sum
mean
x$count <- 1
agg <- aggregate(. ~ id1 + id2, data = x,FUN = sum)
agg
# id1 id2 val1 val2 count
# 1 a x 3 13 2
# 2 b x 4 16 2
# 3 a y 7 14 2
# 4 b y 6 12 2
agg[c("val1", "val2")] <- agg[c("val1", "val2")] / agg$count
agg
# id1 id2 val1 val2 count
# 1 a x 1.5 6.5 2
# 2 b x 2.0 8.0 2
# 3 a y 3.5 7.0 2
# 4 b y 3.0 6.0 2
它的优点是保留列名并创建单个列。count
鉴于这个问题:
我可以使用 plyr 包,但我的数据集非常大,当数据集的大小增长时,plyr 非常慢(几乎无法使用)。
那么在data.table
()中,你可以试试:1.9.4+
> DT
id1 id2 val1 val2
1: a x 1 9
2: a x 2 4
3: a y 3 5
4: a y 4 9
5: b x 1 7
6: b y 4 4
7: b x 3 9
8: b y 2 8
> DT[ , .(mean(val1), mean(val2), .N), by = .(id1, id2)] # simplest
id1 id2 V1 V2 N
1: a x 1.5 6.5 2
2: a y 3.5 7.0 2
3: b x 2.0 8.0 2
4: b y 3.0 6.0 2
> DT[ , .(val1.m = mean(val1), val2.m = mean(val2), count = .N), by = .(id1, id2)] # named
id1 id2 val1.m val2.m count
1: a x 1.5 6.5 2
2: a y 3.5 7.0 2
3: b x 2.0 8.0 2
4: b y 3.0 6.0 2
> DT[ , c(lapply(.SD, mean), count = .N), by = .(id1, id2)] # mean over all columns
id1 id2 val1 val2 count
1: a x 1.5 6.5 2
2: a y 3.5 7.0 2
3: b x 2.0 8.0 2
4: b y 3.0 6.0 2
对于时间比较(用于问题和所有其他 3 个答案)以查看此基准(和案例)。aggregate
data.table
agg
agg.x
使用该软件包,您可以通过使用 .使用此 summarise-function,您可以将其他函数(在本例中为 和 )应用于每个非分组列:dplyr
summarise_all
mean
n()
x %>%
group_by(id1, id2) %>%
summarise_all(funs(mean, n()))
这给了:
id1 id2 val1_mean val2_mean val1_n val2_n
1 a x 1.5 6.5 2 2
2 a y 3.5 7.0 2 2
3 b x 2.0 8.0 2 2
4 b y 3.0 6.0 2 2
如果不想将函数应用于所有非分组列,请指定应应用这些函数的列,或者使用函数用减号排除不需要的列:summarise_at()
# inclusion
x %>%
group_by(id1, id2) %>%
summarise_at(vars(val1, val2), funs(mean, n()))
# exclusion
x %>%
group_by(id1, id2) %>%
summarise_at(vars(-val2), funs(mean, n()))
您还可以使用 来引入多个函数:plyr::each()
aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = plyr::each(avg = mean, n = length))
在版本 1.0.0 之后,上述函数被 取代,您可以在其中选择要操作的列(此处)。dplyr
summarize_all
summarize_at
summarize(across(...))
val1:val2
我们还可以在 中提供函数列表,并使用胶水规范设置列名(= 原始列名,= 列表中的函数名)。across
{.col}
{.fn}
更多信息可以在官方文档中找到。across
library(dplyr)
x %>% group_by(id1, id2) %>%
summarize(across(val1:val2, list(mean = mean, n = length), .names = "{.col}_{.fn}"))
# A tibble: 4 × 6
# Groups: id1 [2]
id1 id2 val1_mean val1_n val2_mean val2_n
<chr> <chr> <dbl> <int> <dbl> <int>
1 a x 1.5 2 6.5 2
2 a y 3.5 2 7 2
3 b x 2 2 8 2
4 b y 3 2 6 2
上一个:连接字符串/字符向量
下一个:计算每个组内的行数
评论
aggregate
by
tapply