我有一个data.frame,我需要计算每组的平均值(即下面的每个Month)。

Name     Month  Rate1     Rate2
Aira       1      12        23
Aira       2      18        73
Aira       3      19        45
Ben        1      53        19
Ben        2      22        87
Ben        3      19        45
Cat        1      22        87
Cat        2      67        43
Cat        3      45        32


我想要的输出如下所示,其中Rate1Rate2的值是组均值。请忽略该值,我已经在示例中进行了弥补。

Name       Rate1       Rate2
Aira        23.21       12.2
Ben         45.23       43.9
Cat         33.22       32.2


评论

这可能是有用的R分组功能

如果还有更多的列(例如,名字,姓氏和地址)而不是仅按名称分组,该怎么办?

#1 楼

这种类型的操作正是aggregate设计的目的:

d <- read.table(text=
'Name     Month  Rate1     Rate2
Aira       1      12        23
Aira       2      18        73
Aira       3      19        45
Ben        1      53        19
Ben        2      22        87
Ben        3      19        45
Cat        1      22        87
Cat        2      67        43
Cat        3      45        32', header=TRUE)

aggregate(d[, 3:4], list(d$Name), mean)

  Group.1    Rate1    Rate2
1    Aira 16.33333 47.00000
2     Ben 31.33333 50.33333
3     Cat 44.66667 54.00000


这里我们汇总data.frame d的第3列和第4列,按d$Name分组,并应用mean函数。


或者使用公式接口:

aggregate(. ~ Name, d[-2], mean)


评论


是的,通过将其更改为aggregate(d [,3:4],list(Name = d $ Name),平均值)

– jbaums
2014年2月24日9:17



当使用aggregate(as.numeric(matrix $ value),list(matrix $ hour),mean)时,由于某种原因,我得到了一些NaN值。检查我的data.table中的is.nan()和is.na()不会显示任何结果。有什么想法吗?

– jdepypere
2015年5月11日23:12

@jdepypere-不知道为什么,但是仔细查看split(matrix $ value,matrix $ hour)的元素可能会有所帮助,这些元素与从您的集合中返回NaN的元素相​​对应(即split(matrix $ value, matrix $ hour)[is.nan(aggregate(as.numeric(matrix $ value),list(matrix $ hour),mean)[,2])])

– jbaums
2015年5月11日23:25

好答案。聚合(d [,3:4],列表(d [,1]),均值)或聚合(d [,c('Rate1','Rate2')],list(d [,c('Name' )]),意思是)更“一致”,恕我直言。

–PatrickT
16 Jun 19'在7:04



@FabianHabersack您将结果与原始数据合并,但是您需要为聚合对象使用不同的名称。使用dplyr可以轻松完成所需的工作:d%>%group_by(Name)%>%mutate(mean1 = mean(Rate1),mean2 = mean(Rate2))

– jbaums
19年5月29日在9:48



#2 楼

或使用group_by软件包中的summarise_atdplyr

library(dplyr)

d %>%
  group_by(Name) %>%
  summarise_at(vars(-Month), funs(mean(., na.rm=TRUE)))

# A tibble: 3 x 3
  Name  Rate1 Rate2
  <fct> <dbl> <dbl>
1 Aira   16.3  47.0
2 Ben    31.3  50.3
3 Cat    44.7  54.0


有关指定作用于变量的多种方法,请参见?summarise_at。在这里,vars(-Month)表示除Month之外的所有变量。

评论


总结_each在新版本中已弃用。我应该使用intead?我尝试了summarise_at或_if or_all。但是没用。

–ferrelwill
17年4月4日在22:22

尝试d%>%group_by(Name)%>%summarise_at(.vars = names(。)[3:4] ,. funs = c(mean =“ mean”))

– CER
18年1月19日在19:51

#3 楼

您还可以使用软件包plyr,它以某种方式更加通用:

library(plyr)

ddply(d, .(Name), summarize,  Rate1=mean(Rate1), Rate2=mean(Rate2))

  Name    Rate1    Rate2
1 Aira 16.33333 47.00000
2  Ben 31.33333 50.33333
3  Cat 44.66667 54.00000


#4 楼

第三种不错的选择是使用软件包data.table,该软件包也具有data.frame类,但是像您正在查找的操作的计算速度要快得多。

library(data.table)
mydt <- structure(list(Name = c("Aira", "Aira", "Aira", "Ben", "Ben", "Ben", "Cat", "Cat", "Cat"), Month = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Rate1 = c(15.6396600443877, 2.15649279424609, 6.24692918928743, 2.37658797276116, 34.7500663272292, 3.28750138697048, 29.3265553981065, 17.9821839334431, 10.8639802575958), Rate2 = c(17.1680489538369, 5.84231656330206, 8.54330866437461, 5.88415184986176, 3.02064294862551, 17.2053351400752, 16.9552950199166, 2.56058000170089, 15.7496228048122)), .Names = c("Name", "Month", "Rate1", "Rate2"), row.names = c(NA, -9L), class = c("data.table", "data.frame"))
为每个人(姓名)取所有三个月的Rate1和Rate2的平均值:
首先,确定要取平均值的平均值

colstoavg <- names(mydt)[3:4]


现在,我们使用lapply对要平均的列取平均值(colstoavg)

mydt.mean <- mydt[,lapply(.SD,mean,na.rm=TRUE),by=Name,.SDcols=colstoavg]

 mydt.mean
   Name     Rate1     Rate2
1: Aira  8.014361 10.517891
2:  Ben 13.471385  8.703377
3:  Cat 19.390907 11.755166


评论


是否有必要甚至在data.tables中使用lapply?

–Herman牙刷
19年11月10日在16:47

@HermanToothrot我至少会这样说。特别是在这种情况下,通过使用.SDcols,他们精确地指定了要将功能应用到哪些列。如果您可以想象有一个data.table包含大量列的情况,则可以首先获取所有数字列的名称,然后使用.SDcols = numericVars进行设置,而不必尝试命名它们全部在j列中。另一个实例正在使用:=在适当位置分配值.SD:= lapply(.SD,f)

– cnolte
7月4日3:06

#5 楼

我描述了两种方法,一种基于data.table,另一种基于reshape2 package。 data.table的方式已经有了答案,但是我试图使其更整洁和详细。

数据是这样的:

 d <- structure(list(Name = structure(c(1L, 1L, 1L, 2L, 2L, 2L, 3L, 
3L, 3L), .Label = c("Aira", "Ben", "Cat"), class = "factor"), 
    Month = c(1L, 2L, 3L, 1L, 2L, 3L, 1L, 2L, 3L), Rate1 = c(12L, 
    18L, 19L, 53L, 22L, 19L, 22L, 67L, 45L), Rate2 = c(23L, 73L, 
    45L, 19L, 87L, 45L, 87L, 43L, 32L)), .Names = c("Name", "Month", 
"Rate1", "Rate2"), class = "data.frame", row.names = c(NA, -9L
))
head(d)
  Name Month Rate1 Rate2
1 Aira     1    12    23
2 Aira     2    18    73
3 Aira     3    19    45
4  Ben     1    53    19
5  Ben     2    22    87
6  Ben     3    19    45


library("reshape2")
mym <- melt(d, id = c("Name"))
res <- dcast(mym, Name ~ variable, mean)
res
#Name Month    Rate1    Rate2
#1 Aira     2 16.33333 47.00000
#2  Ben     2 31.33333 50.33333
#3  Cat     2 44.66667 54.00000


使用data.table:

# At first, I convert the data.frame to data.table and then I group it 
setDT(d)
d[, .(Rate1 = mean(Rate1), Rate2 = mean(Rate2)), by = .(Name)]
#   Name    Rate1    Rate2
#1: Aira 16.33333 47.00000
#2:  Ben 31.33333 50.33333
#3:  Cat 44.66667 54.00000


还有另一种方法,避免使用.SD
d[, lapply(.SD, mean), by = .(Name)]
#   Name Month    Rate1    Rate2
#1: Aira     2 16.33333 47.00000
#2:  Ben     2 31.33333 50.33333
#3:  Cat     2 44.66667 54.00000


如果我们只想拥有Rate1和Rate2,则可以如下使用.SDcols:

d[, lapply(.SD, mean), by = .(Name), .SDcols = 3:4]
#  Name    Rate1    Rate2
#1: Aira 16.33333 47.00000
#2:  Ben 31.33333 50.33333
#3:  Cat 44.66667 54.00000


评论


刚刚意识到虽然已经有了答案:stackoverflow.com/a/22004271/559784

–阿伦
16年5月25日在18:41

#6 楼

这是在基本R中执行此操作的多种方法,包括可选的aggregate方法。下面的示例每月返回平均值,我认为这是您所要求的。虽然,可以使用相同的方法来返回每人的均值:
使用ave
my.data <- read.table(text = '
     Name     Month  Rate1     Rate2
     Aira       1      12        23
     Aira       2      18        73
     Aira       3      19        45
     Ben        1      53        19
     Ben        2      22        87
     Ben        3      19        45
     Cat        1      22        87
     Cat        2      67        43
     Cat        3      45        32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')

Rate1.mean <- with(my.data, ave(Rate1, Month, FUN = function(x) mean(x, na.rm = TRUE)))
Rate2.mean <- with(my.data, ave(Rate2, Month, FUN = function(x) mean(x, na.rm = TRUE)))

my.data <- data.frame(my.data, Rate1.mean, Rate2.mean)
my.data

使用by
my.data <- read.table(text = '
     Name     Month  Rate1     Rate2
     Aira       1      12        23
     Aira       2      18        73
     Aira       3      19        45
     Ben        1      53        19
     Ben        2      22        87
     Ben        3      19        45
     Cat        1      22        87
     Cat        2      67        43
     Cat        3      45        32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')

by.month <- as.data.frame(do.call("rbind", by(my.data, my.data$Month, FUN = function(x) colMeans(x[,3:4]))))
colnames(by.month) <- c('Rate1.mean', 'Rate2.mean')
by.month <- cbind(Month = rownames(by.month), by.month)

my.data <- merge(my.data, by.month, by = 'Month')
my.data

使用lapplysplit
my.data <- read.table(text = '
     Name     Month  Rate1     Rate2
     Aira       1      12        23
     Aira       2      18        73
     Aira       3      19        45
     Ben        1      53        19
     Ben        2      22        87
     Ben        3      19        45
     Cat        1      22        87
     Cat        2      67        43
     Cat        3      45        32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')

ly.mean <- lapply(split(my.data, my.data$Month), function(x) c(Mean = colMeans(x[,3:4])))
ly.mean <- as.data.frame(do.call("rbind", ly.mean))
ly.mean <- cbind(Month = rownames(ly.mean), ly.mean)

my.data <- merge(my.data, ly.mean, by = 'Month')
my.data

使用sapplysplit
my.data <- read.table(text = '
     Name     Month  Rate1     Rate2
     Aira       1      12        23
     Aira       2      18        73
     Aira       3      19        45
     Ben        1      53        19
     Ben        2      22        87
     Ben        3      19        45
     Cat        1      22        87
     Cat        2      67        43
     Cat        3      45        32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')
my.data

sy.mean <- t(sapply(split(my.data, my.data$Month), function(x) colMeans(x[,3:4])))
colnames(sy.mean) <- c('Rate1.mean', 'Rate2.mean')
sy.mean <- data.frame(Month = rownames(sy.mean), sy.mean, stringsAsFactors = FALSE)
my.data <- merge(my.data, sy.mean, by = 'Month')
my.data

使用aggregate
my.data <- read.table(text = '
     Name     Month  Rate1     Rate2
     Aira       1      12        23
     Aira       2      18        73
     Aira       3      19        45
     Ben        1      53        19
     Ben        2      22        87
     Ben        3      19        45
     Cat        1      22        87
     Cat        2      67        43
     Cat        3      45        32
', header = TRUE, stringsAsFactors = FALSE, na.strings = 'NA')

my.summary <- with(my.data, aggregate(list(Rate1, Rate2), by = list(Month), 
                   FUN = function(x) { mon.mean = mean(x, na.rm = TRUE) } ))

my.summary <- do.call(data.frame, my.summary)
colnames(my.summary) <- c('Month', 'Rate1.mean', 'Rate2.mean')
my.summary

my.data <- merge(my.data, my.summary, by = 'Month')
my.data

编辑:2020年6月28日
这里我使用aggregate来获取列按组划分的整个meansmatrix,其中在外部vector中定义了组:
my.group <- c(1,2,1,2,2,3,1,2,3,3)

my.data <- matrix(c(   1,    2,    3,    4,    5,
                      10,   20,   30,   40,   50,
                       2,    4,    6,    8,   10,
                      20,   30,   40,   50,   60,
                      20,   18,   16,   14,   12,
                    1000, 1100, 1200, 1300, 1400,
                       2,    3,    4,    3,    2,
                      50,   40,   30,   20,   10,
                    1001, 2001, 3001, 4001, 5001,
                    1000, 2000, 3000, 4000, 5000), nrow = 10, ncol = 5, byrow = TRUE)
my.data

my.summary <- aggregate(list(my.data), by = list(my.group), FUN = function(x) { my.mean = mean(x, na.rm = TRUE) } )
my.summary
#  Group.1          X1       X2          X3       X4          X5
#1       1    1.666667    3.000    4.333333    5.000    5.666667
#2       2   25.000000   27.000   29.000000   31.000   33.000000
#3       3 1000.333333 1700.333 2400.333333 3100.333 3800.333333


#7 楼

您也可以使用通用函数cbind()lm()而不使用截距:

cbind(lm(d$Rate1~-1+d$Name)$coef,lm(d$Rate2~-1+d$Name)$coef)
>               [,1]     [,2]
>d$NameAira 16.33333 47.00000
>d$NameBen  31.33333 50.33333
>d$NameCat  44.66667 54.00000


#8 楼

您还可以使用sqldf软件包来完成此操作,如下所示:

library(sqldf)

x <- read.table(text='Name     Month  Rate1     Rate2
Aira       1      12        23
                Aira       2      18        73
                Aira       3      19        45
                Ben        1      53        19
                Ben        2      22        87
                Ben        3      19        45
                Cat        1      22        87
                Cat        2      67        43
                Cat        3      45        32', header=TRUE)

sqldf("
select 
  Name
  ,avg(Rate1) as Rate1_float
  ,avg(Rate2) as Rate2_float
  ,avg(Rate1) as Rate1
  ,avg(Rate2) as Rate2
from x
group by 
  Name
")

#  Name Rate1_float Rate2_float Rate1 Rate2
#1 Aira    16.33333    47.00000    16    47
#2  Ben    31.33333    50.33333    31    50
#3  Cat    44.66667    54.00000    44    54


我最近转换为dplyr,如其他答案所示,但sqldf可以作为大多数数据使用分析师/数据科学家/开发人员至少精通SQL。这样,我认为它比dplyr或上面介绍的其他解决方案更倾向于使代码更具通用性。

UPDATE:在回应下面的评论时,我试图更新如上所示的代码。但是,该行为不符合我的预期。似乎只有在列别名与原始列名匹配时才执行列定义(即intfloat)。当您指定新名称时,将返回聚合列而不进行舍入。

评论


您能对四舍五入发表评论吗?

–PatrickT
16年6月19日在7:23

@partickt,您好(抱歉造成延迟),这是SQL的细微差别,在此进行描述:stackoverflow.com/questions/18493976/…。如您所见,由于SQL以int开头,因此将其保留为int。 avg(cast(Ratei as float))应该得到一个十进制值,可以根据需要用round换行。 avg(Ratei * 1.0)也应强制为浮点数...也没有运行

– joemienko
16年6月21日在16:21