R 在一次调用中按组对多个变量应用多个摘要函数
我有以下数据框R 在一次调用中按组对多个变量应用多个摘要函数,r,aggregate,r-faq,R,Aggregate,R Faq,我有以下数据框 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) 为了在一次调用中完成这两个计算,我
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)
为了在一次调用中完成这两个计算,我尝试了
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, 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列和两个矩阵列的数据帧:
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所指出的,通过使用do.call(data.frame,…)
这是LHS上多个变量的语法:
aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = function(x) c(mn = mean(x), n = length(x) ) )
您可以添加一个count
列,使用sum
进行聚合,然后向后缩放以获得平均值
:
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
x$count鉴于问题中的这一点:
我可以使用plyr包,但是我的数据集非常大,当数据集的大小增加时,plyr非常慢(几乎无法使用)
然后在(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个其他答案)与数据进行比较的计时,请参见表
(agg
和agg.x
案例)。。使用此汇总功能,您可以将其他功能(在本例中为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
如果不想将该函数应用于所有非分组列,可以指定应将其应用于的列,或者使用summary_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))
另一个dplyr
选项是cross
,它是当前开发版本的一部分
#devtools::install_github("tidyverse/dplyr")
library(dplyr)
x %>%
group_by(id1, id2) %>%
summarise(across(starts_with("val"), list(mean = mean, n = length)))
结果
# A tibble: 4 x 4
# Groups: id1 [2]
id1 id2 mean$val1 $val2 n$val1 $val2
<fct> <fct> <dbl> <dbl> <int> <int>
1 a x 1.5 6.5 2 2
2 a y 3.5 7 2 2
3 b x 2 8 2 2
4 b y 3 6 2 2
多谢。作为旁注,如何使聚合只对一列进行汇总。如果我有几个数字列,我不希望它对我不希望的列求和。我当然可以在聚合完成后扔掉这些列,但是CPU周期已经用掉了。你只给它要分组的因子和要聚合的列。可能在数据中使用负列索引,或者将所需的列放在公式的左侧。(参见编辑)在Windows7机器上使用RStudio 0.98.1014时,我遇到了user2659402在其更新中提到的错误。如果您将数据帧输出到控制台(如图所示),它看起来正常,但是如果您将其保存到d中,然后尝试访问d$val1.mn,它将返回NULL。如果运行视图(d),d也会显示格式不正确。使用更新中的代码修复了它。您遇到困难的原因是“VAL”作为矩阵返回,每个矩阵有两列,而不是作为普通列返回。尝试d$val1[,“mn”]
并使用str
查看结构。您可以将包含矩阵的列绑定回数据框:agg在aggregate
旁边回答中提到的还有by
和tapply
。
aggregate(cbind(val1, val2) ~ id1 + id2, data = x, FUN = plyr::each(avg = mean, n = length))
#devtools::install_github("tidyverse/dplyr")
library(dplyr)
x %>%
group_by(id1, id2) %>%
summarise(across(starts_with("val"), list(mean = mean, n = length)))
# A tibble: 4 x 4
# Groups: id1 [2]
id1 id2 mean$val1 $val2 n$val1 $val2
<fct> <fct> <dbl> <dbl> <int> <int>
1 a x 1.5 6.5 2 2
2 a y 3.5 7 2 2
3 b x 2 8 2 2
4 b y 3 6 2 2
packageVersion("dplyr")
[1] ‘0.8.99.9000’