我想将data.frame中的数据分组为两列,然后对特定的第三列求和。例如:
> aggregate(mpg~gear+cyl, data=mtcars, FUN=sum)
gear cyl mpg
1 3 4 21.5
2 4 4 215.4
3 5 4 56.4
4 3 6 39.5
5 4 6 79.0
6 5 6 19.7
7 3 8 180.6
8 5 8 30.8
现在,我需要为不同的列多次执行此操作。所以我想编写一个概括它的函数。它采用data.frame和其中一个列(为了简单起见)并做同样的事情。
agg.data <- function(df, colname) {
aggregate(mpg~gear+colname, data=df, FUN=sum)
}
运行它将产生:
Error in eval(expr, envir, enclos) : object 'colname' not found
如何将colname的值传递给聚合?
答案 0 :(得分:7)
将公式的字符串表示粘贴在一起,并将该字符串作为参数提供给公式()...
agg.data <- function(df, colname) {
aggregate(formula(paste0("mpg~gear+", colname)), data=df, FUN=sum)
}
> agg.data(mtcars, "cyl")
gear cyl mpg
1 3 4 21.5
2 4 4 215.4
3 5 4 56.4
4 3 6 39.5
5 4 6 79.0
6 5 6 19.7
7 3 8 180.6
8 5 8 30.8
答案 1 :(得分:2)
使用data.table
:
fun.dt <- function(dt, col) {
dt[, .(mpg=sum(mpg)), by=c("gear", col)]
}
require(data.table)
dt = as.data.table(mtcars)
fun.dt(dt, "cyl")
# gear cyl mpg
# 1: 4 6 79.0
# 2: 4 4 215.4
# 3: 3 6 39.5
# 4: 3 8 180.6
# 5: 3 4 21.5
# 6: 5 4 56.4
# 7: 5 8 30.8
# 8: 5 6 19.7
data.tables 中的by
表达式除了列/表达式列表外,还可以采用列名的字符向量。我们可以简单地为by
参数提供一个字符向量。
答案 2 :(得分:1)
您可以轻松使用&#34;普通&#34; aggregate
接口(即不是公式接口)提供变量中的列名。语法略有不同,但仍然很容易,并且不需要粘贴:
agg.data2 <- function(df, colname) {
aggregate(df[["mpg"]], list(df[["gear"]], df[[colname]]), FUN=sum)
}
agg.data2(mtcars, "cyl")
# Group.1 Group.2 x
#1 3 4 21.5
#2 4 4 215.4
#3 5 4 56.4
#4 3 6 39.5
#5 4 6 79.0
#6 5 6 19.7
#7 3 8 180.6
#8 5 8 30.8
这是dplyr的等价物:
library(dplyr)
agg.data.dplyr <- function(df, colname) {
df %>%
group_by_(.dots = c("gear", colname)) %>%
summarise(sum = sum(mpg)) %>%
ungroup()
}
agg.data.dplyr(mtcars, "cyl")
答案 3 :(得分:1)
您还可以使用deparse
和substitute
agg.data <- function(df, colname) {
aggregate(df$mpg, list(df$gear, df[, deparse(substitute(colname))]), FUN=sum)
}
agg.data(mtcars, cyl)
# Group.1 Group.2 x
# 1 3 4 21.5
# 2 4 4 215.4
# 3 5 4 56.4
# 4 3 6 39.5
# 5 4 6 79.0
# 6 5 6 19.7
# 7 3 8 180.6
# 8 5 8 30.8
答案 4 :(得分:0)
您还可以使用ggplot
或with
的方式执行此操作,这样您只需按原样编写组合名,而无需使用substitute
传递字符串。
agg.data3 = function (df, colname){
colname = substitute(colname)
colname = as.character(colname)
aggregate(formula(paste0("mpg~gear+", colname)), data=mtcars, FUN=sum)
}
使用
agg.data3(cars, cyl)
答案 5 :(得分:0)
您可能应该在tidyverse上找到一个函数,但是,有一个我经常用于汇总汇总的函数。它嵌入了上面与formula()
讨论过的大部分内容,但形式更为笼统:
get.stat = function(df,var.nm,agg.id){
#--- df data.frame for aggregation
#--- var.nm target variable to be aggregated
#--- agg.id index name for aggretation (single value or vector)
#--- generate aggregation formula
agg.formula = paste(agg.id, collapse = "+")
#--- df with summary results
df.res = data.frame(mean = aggregate(formula(paste0(var.nm,"~",agg.formula)), df, mean )[,length(agg.id)+1],
median = aggregate(formula(paste0(var.nm,"~",agg.formula)), df, median)[,length(agg.id)+1],
sd = aggregate(formula(paste0(var.nm,"~",agg.formula)), df, sd )[,length(agg.id)+1],
min = aggregate(formula(paste0(var.nm,"~",agg.formula)), df, min )[,length(agg.id)+1],
max = aggregate(formula(paste0(var.nm,"~",agg.formula)), df, max )[,length(agg.id)+1],
sum = aggregate(formula(paste0(var.nm,"~",agg.formula)), df, sum )[,length(agg.id)+1],
count = aggregate(formula(paste0(var.nm,"~",agg.formula)), df, length)[,length(agg.id)+1])
#--- bind indexers
for(c in 1:length(agg.id)){
df.res = cbind(df.res, aggregate(formula(paste0(var.nm,"~",agg.formula)), df, mean)[,c])
colnames(df.res)[length(colnames(df.res))] = agg.id[c]
}
#--- re-order col
df.res = df.res[,c(agg.id,colnames(df.res)[1:(length(colnames(df.res)) - c)])]
return(df.res)
}
加载该功能后,您可以简单地:
get.stat(df, "mpg",c("gear","cyl"))