452

我有一个包含两列的数据框。第一列包含“First”、“Second”、“Third”等类别,第二列包含代表我从“Category”中看到特定组的次数的数字。

例如:

Category     Frequency
First        10
First        15
First        5
Second       2
Third        14
Third        20
Second       3

我想按类别对数据进行排序并将所有频率相加:

Category     Frequency
First        30
Second       5
Third        34

我将如何在 R 中做到这一点?

4

15 回答 15

474

使用aggregate

aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum)
  Category  x
1    First 30
2   Second  5
3    Third 34

在上面的示例中,可以在list. 可以通过以下方式合并相同数据类型的多个聚合指标cbind

aggregate(cbind(x$Frequency, x$Metric2, x$Metric3) ...

(嵌入@thelatemail 评论),aggregate也有公式界面

aggregate(Frequency ~ Category, x, sum)

或者,如果您想聚合多列,您可以使用.符号(也适用于一列)

aggregate(. ~ Category, x, sum)

tapply

tapply(x$Frequency, x$Category, FUN=sum)
 First Second  Third 
    30      5     34 

使用这些数据:

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                      "Third", "Third", "Second")), 
                    Frequency=c(10,15,5,2,14,20,3))
于 2009-11-02T12:52:46.003 回答
345

您还可以为此目的使用dplyr包:

library(dplyr)
x %>% 
  group_by(Category) %>% 
  summarise(Frequency = sum(Frequency))

#Source: local data frame [3 x 2]
#
#  Category Frequency
#1    First        30
#2   Second         5
#3    Third        34

或者,对于多个汇总列(也适用于一列):

x %>% 
  group_by(Category) %>% 
  summarise(across(everything(), sum))

以下是一些关于如何使用内置数据集的 dplyr 函数按组汇总数据的更多示例mtcars

# several summary columns with arbitrary names
mtcars %>% 
  group_by(cyl, gear) %>%                            # multiple group columns
  summarise(max_hp = max(hp), mean_mpg = mean(mpg))  # multiple summary columns

# summarise all columns except grouping columns using "sum" 
mtcars %>% 
  group_by(cyl) %>% 
  summarise(across(everything(), sum))

# summarise all columns except grouping columns using "sum" and "mean"
mtcars %>% 
  group_by(cyl) %>% 
  summarise(across(everything(), list(mean = mean, sum = sum)))

# multiple grouping columns
mtcars %>% 
  group_by(cyl, gear) %>% 
  summarise(across(everything(), list(mean = mean, sum = sum)))

# summarise specific variables, not all
mtcars %>% 
  group_by(cyl, gear) %>% 
  summarise(across(c(qsec, mpg, wt), list(mean = mean, sum = sum)))

# summarise specific variables (numeric columns except grouping columns)
mtcars %>% 
  group_by(gear) %>% 
  summarise(across(where(is.numeric), list(mean = mean, sum = sum)))

有关更多信息,包括%>%运算符,请参阅dplyr 简介

于 2014-12-03T08:02:19.943 回答
82

rcs 提供的答案很简单。但是,如果您正在处理更大的数据集并需要提高性能,则有一个更快的替代方案:

library(data.table)
data = data.table(Category=c("First","First","First","Second","Third", "Third", "Second"), 
                  Frequency=c(10,15,5,2,14,20,3))
data[, sum(Frequency), by = Category]
#    Category V1
# 1:    First 30
# 2:   Second  5
# 3:    Third 34
system.time(data[, sum(Frequency), by = Category] )
# user    system   elapsed 
# 0.008     0.001     0.009 

让我们将其与使用 data.frame 和上面的内容进行比较:

data = data.frame(Category=c("First","First","First","Second","Third", "Third", "Second"),
                  Frequency=c(10,15,5,2,14,20,3))
system.time(aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum))
# user    system   elapsed 
# 0.008     0.000     0.015 

如果您想保留该列,请使用以下语法:

data[,list(Frequency=sum(Frequency)),by=Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34

使用更大的数据集,这种差异将变得更加明显,如下面的代码所示:

data = data.table(Category=rep(c("First", "Second", "Third"), 100000),
                  Frequency=rnorm(100000))
system.time( data[,sum(Frequency),by=Category] )
# user    system   elapsed 
# 0.055     0.004     0.059 
data = data.frame(Category=rep(c("First", "Second", "Third"), 100000), 
                  Frequency=rnorm(100000))
system.time( aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum) )
# user    system   elapsed 
# 0.287     0.010     0.296 

对于多个聚合,可以组合lapply.SD如下

data[, lapply(.SD, sum), by = Category]
#    Category Frequency
# 1:    First        30
# 2:   Second         5
# 3:    Third        34
于 2013-09-08T17:50:16.773 回答
43

您还可以使用by()函数:

x2 <- by(x$Frequency, x$Category, sum)
do.call(rbind,as.list(x2))

那些其他包(plyr、reshape)具有返回 data.frame 的好处,但值得熟悉 by(),因为它是一个基本函数。

于 2009-11-02T17:42:07.103 回答
33

几年后,只是为了添加另一个简单的基本 R 解决方案,由于某种原因这里不存在 -xtabs

xtabs(Frequency ~ Category, df)
# Category
# First Second  Third 
#    30      5     34 

或者如果你想要一个data.frame背部

as.data.frame(xtabs(Frequency ~ Category, df))
#   Category Freq
# 1    First   30
# 2   Second    5
# 3    Third   34
于 2015-09-10T13:36:01.400 回答
31
library(plyr)
ddply(tbl, .(Category), summarise, sum = sum(Frequency))
于 2009-11-02T09:44:34.393 回答
26

如果x是包含您的数据的数据框,那么以下内容将执行您想要的操作:

require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)
于 2009-11-02T09:38:41.783 回答
22

虽然我最近已经成为dplyr大多数此类操作的转换者,但sqldf对于某些事情,该包仍然非常好(恕我直言,更具可读性)。

这是一个如何回答这个问题的例子sqldf

x <- data.frame(Category=factor(c("First", "First", "First", "Second",
                                  "Third", "Third", "Second")), 
                Frequency=c(10,15,5,2,14,20,3))

sqldf("select 
          Category
          ,sum(Frequency) as Frequency 
       from x 
       group by 
          Category")

##   Category Frequency
## 1    First        30
## 2   Second         5
## 3    Third        34
于 2016-05-17T12:12:56.623 回答
20

只是添加第三个选项:

require(doBy)
summaryBy(Frequency~Category, data=yourdataframe, FUN=sum)

编辑:这是一个非常古老的答案。现在我建议使用group_byand summarisefrom dplyr,就像@docendo 的答案一样。

于 2009-11-02T12:15:52.543 回答
9

另一种在矩阵或数据框中按组返回和的解决方案又短又快:

rowsum(x$Frequency, x$Category)
于 2020-04-28T11:14:26.323 回答
8

ave当您需要在不同的列上应用不同的聚合函数(并且您必须/想要坚持使用基础 R)时,我发现非常有帮助(并且有效):

例如

鉴于此输入:

DF <-                
data.frame(Categ1=factor(c('A','A','B','B','A','B','A')),
           Categ2=factor(c('X','Y','X','X','X','Y','Y')),
           Samples=c(1,2,4,3,5,6,7),
           Freq=c(10,30,45,55,80,65,50))

> DF
  Categ1 Categ2 Samples Freq
1      A      X       1   10
2      A      Y       2   30
3      B      X       4   45
4      B      X       3   55
5      A      X       5   80
6      B      Y       6   65
7      A      Y       7   50

我们想按Categ1和分组Categ2并计算 的总和Samples和 的平均值Freq
这是一个可能的解决方案ave

# create a copy of DF (only the grouping columns)
DF2 <- DF[,c('Categ1','Categ2')]

# add sum of Samples by Categ1,Categ2 to DF2 
# (ave repeats the sum of the group for each row in the same group)
DF2$GroupTotSamples <- ave(DF$Samples,DF2,FUN=sum)

# add mean of Freq by Categ1,Categ2 to DF2 
# (ave repeats the mean of the group for each row in the same group)
DF2$GroupAvgFreq <- ave(DF$Freq,DF2,FUN=mean)

# remove the duplicates (keep only one row for each group)
DF2 <- DF2[!duplicated(DF2),]

结果 :

> DF2
  Categ1 Categ2 GroupTotSamples GroupAvgFreq
1      A      X               6           45
2      A      Y               9           40
3      B      X               7           50
6      B      Y               6           65
于 2018-12-10T16:55:13.953 回答
7

由于dplyr 1.0.0across()可以使用该函数:

df %>%
 group_by(Category) %>%
 summarise(across(Frequency, sum))

  Category Frequency
  <chr>        <int>
1 First           30
2 Second           5
3 Third           34

如果对多个变量感兴趣:

df %>%
 group_by(Category) %>%
 summarise(across(c(Frequency, Frequency2), sum))

  Category Frequency Frequency2
  <chr>        <int>      <int>
1 First           30         55
2 Second           5         29
3 Third           34        190

并使用选择助手选择变量:

df %>%
 group_by(Category) %>%
 summarise(across(starts_with("Freq"), sum))

  Category Frequency Frequency2 Frequency3
  <chr>        <int>      <int>      <dbl>
1 First           30         55        110
2 Second           5         29         58
3 Third           34        190        380

样本数据:

df <- read.table(text = "Category Frequency Frequency2 Frequency3
                 1    First        10         10         20
                 2    First        15         30         60
                 3    First         5         15         30
                 4   Second         2          8         16
                 5    Third        14         70        140
                 6    Third        20        120        240
                 7   Second         3         21         42",
                 header = TRUE,
                 stringsAsFactors = FALSE)
于 2020-06-14T15:14:36.180 回答
6

您可以使用group.sumRfast的功能。

Category <- Rfast::as_integer(Category,result.sort=FALSE) # convert character to numeric. R's as.numeric produce NAs.
result <- Rfast::group.sum(Frequency,Category)
names(result) <- Rfast::Sort(unique(Category)
# 30 5 34

Rfast有很多组函数,group.sum就是其中之一。

于 2018-11-18T14:11:14.803 回答
5

使用cast代替recast(注意'Frequency'现在'value'

df  <- data.frame(Category = c("First","First","First","Second","Third","Third","Second")
                  , value = c(10,15,5,2,14,20,3))

install.packages("reshape")

result<-cast(df, Category ~ . ,fun.aggregate=sum)

要得到:

Category (all)
First     30
Second    5
Third     34
于 2018-02-25T15:43:56.273 回答
1
library(tidyverse)

x <- data.frame(Category= c('First', 'First', 'First', 'Second', 'Third', 'Third', 'Second'), 
           Frequency = c(10, 15, 5, 2, 14, 20, 3))

count(x, Category, wt = Frequency)

于 2020-10-21T17:03:25.033 回答