R 聚合大量的列

R aggregate by large number of columns

我有一个大约有 40 列的数据框 (df),我想使用其中 4 列的总和进行聚合。在我想要求和的 4 之外,第 1 列中的每个唯一值对应于其余列中的相同值,我想将所有列保留在聚合数据框中。有什么方法可以指定 by = list() 部分中的列,而不必显式键入它们?例如,如果我知道我想按第 1-36 列对 "field" 列求和。我试过了

aggregate(df$field, by = list(df[,1:36]), FUN = sum)

但它会抛出错误,因为那不是姓名列表。我也试过

aggregate(df$field, by = list(names(df)[1:36]), FUN = sum)

虽然这不会出错,但它会返回一个以我的 df 名称作为唯一观察值的聚合。

或者我错过了一个简单的表达方式 "aggregate these four columns using the rest of the data frame?"

谢谢

这是一个示例数据框:

  A B C D Sum
1 A B C D   1
2 A B C D   2
3 A B C D   3
4 E F 1 R   4
5 E F 1 R   5

聚合后我希望它看起来像:

  A B C D Sum
1 A B C D 6
2 E F 1 R 9

我知道如果我在聚合语句的 "by" 部分明确声明 x$A、x$B、x$C、x$D 就可以做到这一点,但在我的实际数据框中将需要明确键入大约 40 个字段名称。

您问的是如何聚合多个变量的总和,并按剩余变量分组。为此,我会先组合多个变量,然后使用(在我看来)更方便的 aggregate 函数公式界面进行聚合。例如,考虑根据剩余变量(Petal.Width 和物种)聚合鸢尾花数据集中 Sepal.Length、Sepal.Width 和 Petal.Length 的总和:

agg <- iris
cols <- c("Sepal.Length", "Sepal.Width", "Petal.Length")
agg$sum <- rowSums(agg[,cols])
agg <- agg[,!names(agg) %in% cols]
aggregate(sum~., data=agg, FUN=sum)
#    Petal.Width    Species   sum
# 1          0.1     setosa  47.8
# 2          0.2     setosa 284.1
# 3          0.3     setosa  68.1
# 4          0.4     setosa  74.6
# 5          0.5     setosa  10.1
# 6          0.6     setosa  10.1
# 7          1.0 versicolor  79.9
# 8          1.1 versicolor  34.3
# 9          1.2 versicolor  63.8
# 10         1.3 versicolor 166.5
# 11         1.4 versicolor  96.7
# 12         1.5 versicolor 136.5
# 13         1.6 versicolor  42.0
# 14         1.7 versicolor  14.7
# 15         1.8 versicolor  13.9
# 16         1.4  virginica  14.3
# 17         1.5  virginica  27.4
# 18         1.6  virginica  16.0
# 19         1.7  virginica  11.9
# 20         1.8  virginica 162.2
# 21         1.9  virginica  71.7
# 22         2.0  virginica  91.3
# 23         2.1  virginica  94.4
# 24         2.2  virginica  48.3
# 25         2.3  virginica 125.6
# 26         2.4  virginica  44.4
# 27         2.5  virginica  48.2

使用@josilber 提到的示例数据,这将是使用 dplyr() 实现所需输出的另一种选择,这对于大型数据集更有效

library('dplyr')

out = agg %>% 
regroup(lapply(names(select(agg, -sum)), as.symbol)) %>% 
summarise_each(funs(sum))

Source: local data frame [27 x 3]
Groups: Species

#  Species Petal.Width   sum
#1      setosa         0.1  47.8
#2      setosa         0.2 284.1
#3      setosa         0.3  68.1
#4      setosa         0.4  74.6
#5      setosa         0.5  10.1
#6      setosa         0.6  10.1
#7  versicolor         1.0  79.9
#8  versicolor         1.1  34.3
#9  versicolor         1.2  63.8
#10 versicolor         1.3 166.5
#..        ...         ...   ...

使用data.table

library('data.table')

out = setDT(agg)[, list(sum = sum(sum)), by= names(agg[,!"sum", with=FALSE])]

#  Species Petal.Width   sum
#1:     setosa         0.2 284.1
#2:     setosa         0.4  74.6
#3:     setosa         0.3  68.1
#4:     setosa         0.1  47.8
#5:     setosa         0.5  10.1
#6:     setosa         0.6  10.1
#7: versicolor         1.4  96.7
#8: versicolor         1.5 136.5
#9: versicolor         1.3 166.5
#10:versicolor         1.6  42.0
# ...

像这样使用 data.frame 方法 (aggregate.data.frame):

aggregate(df["field"], by = df[1:36], FUN = sum)

或者像这样使用公式方法 (aggregate.formula):

nms <- c("field", names(df)[1:36])
aggregate(field ~., df, sum)

以问题末尾的示例数据而言:

Lines <- " A B C D Sum
1 A B C D   1
2 A B C D   2
3 A B C D   3
4 E F 1 R   4
5 E F 1 R   5"
df <- read.table(text = Lines, header = TRUE)

# data.frame method
aggregate(df["Sum"], df[1:4], sum)

# data.frame method - alternative
aggregate(df[5], df[-5], sum)

# formula method
aggregate(Sum ~., df, sum)

这将是 dplyr 的当前答案:

library('dplyr')
mytb<-read.table(text="
A B C D Sum
1 A B C D   1
2 A B C D   2
3 A B C D   3
4 E F 1 R   4
5 E F 1 R   5", header=T, stringsAsFactors=F)

mytb %>% 
  group_by_at(names(select(mytb, -"Sum") ) )  %>% 
  summarise_all(.funs=sum)