按组计算平均值

时间:2012-07-19 14:08:23

标签: r dataframe r-faq

我有一个类似于此的大型数据框:

df <- data.frame(dive=factor(sample(c("dive1","dive2"),10,replace=TRUE)),speed=runif(10))
> df
    dive      speed
1  dive1 0.80668490
2  dive1 0.53349584
3  dive2 0.07571784
4  dive2 0.39518628
5  dive1 0.84557955
6  dive1 0.69121443
7  dive1 0.38124950
8  dive2 0.22536126
9  dive1 0.04704750
10 dive2 0.93561651

我的目标是在另一列等于某个值时平均一列的值,并对所有值重复此操作。即,在上面的示例中,我想为列speed的每个唯一值返回列dive的平均值。因此,当dive==dive1时,speed的平均值为此,依此类推dive的每个值。

6 个答案:

答案 0 :(得分:95)

在R中有很多方法可以做到这一点。具体来说,byaggregatesplitplyrcast,{{1} },tapplydata.table,等等。

从广义上讲,这些问题的形式是分裂 - 应用 - 结合。 Hadley Wickham编写了beautiful article,可以让您更深入地了解整个问题类别,值得一读。他的dplyr包实现了一般数据结构的策略,而plyr是针对数据帧调整的更新的实现性能。它们允许解决相同形式的问题,但比这个问题复杂得多。作为解决数据操作问题的通用工具,它们非常值得学习。

性能是一个非常大的数据集的问题,因此很难打败基于dplyr的解决方案。但是,如果您只处理中型数据集或更小的数据集,那么花时间学习data.table可能不值得。 data.table也可以很快,所以如果你想加快速度,这是一个不错的选择,但并不需要dplyr的可扩展性。

以下许多其他解决方案不需要任何其他解决方案。其中一些甚至在中大型数据集上相当快。它们的主要缺点是隐喻或灵活性。通过隐喻,我的意思是它是一种工具,专为强迫其他东西设计,以便在一个聪明的人中解决这类特殊问题。办法。灵活性,我的意思是他们缺乏解决各种类似问题或轻松产生整洁输出的能力。


实施例

data.table函数

<强> base

tapply

<强> tapply(df$speed, df$dive, mean) # dive1 dive2 # 0.5419921 0.5103974

aggregate接收data.frames,输出data.frames,并使用公式接口。

aggregate

<强> aggregate( speed ~ dive, df, mean ) # dive speed # 1 dive1 0.5790946 # 2 dive2 0.4864489

以其最友好的用户形式,它接收向量并向其应用函数。但是,它的输出不是一种非常易于操作的形式。:

by

为了解决这个问题,对于res.by <- by(df$speed, df$dive, mean) res.by # df$dive: dive1 # [1] 0.5790946 # --------------------------------------- # df$dive: dive2 # [1] 0.4864489 by库中的as.data.frame方法的简单使用,可以使用:

taRifx

<强> library(taRifx) as.data.frame(res.by) # IDX1 value # 1 dive1 0.6736807 # 2 dive2 0.4051447

顾名思义,它只执行&#34;分裂&#34;分裂 - 应用 - 组合策略的一部分。为了完成其余的工作,我将编写一个小函数,使用split进行apply-combine。 sapply会尽可能自动地简化结果。在我们的例子中,这意味着一个向量而不是一个data.frame,因为我们只得到了一维结果。

sapply

外部包

<强> data.table

splitmean <- function(df) {
  s <- split( df, df$dive)
  sapply( s, function(x) mean(x$speed) )
}
splitmean(df)
#     dive1     dive2 
# 0.5790946 0.4864489 

<强> library(data.table) setDT(df)[ , .(mean_speed = mean(speed)), by = dive] # dive mean_speed # 1: dive1 0.5419921 # 2: dive2 0.5103974

dplyr

library(dplyr) group_by(df, dive) %>% summarize(m = mean(speed)) plyr的前提)

以下是official pagedplyr所说的内容:

  

已经可以使用plyr R函数(例如base和}来执行此操作   split系列函数),但apply使一切变得容易   用:

     
      
  • 完全一致的名称,参数和输出
  •   
  • 通过plyr
  • 方便并行化   
  • 输入和输出到data.frames,matrices和lists
  •   
  • 跟踪长时间运行的进度条
  •   
  • 内置错误恢复和信息性错误消息
  •   
  • 在所有转化中维护的标签
  •   

换句话说,如果您学习了一种用于拆分 - 应用 - 组合操作的工具,那么它应该是foreach

plyr

<强> reshape2

library(plyr) res.plyr <- ddply( df, .(dive), function(x) mean(x$speed) ) res.plyr # dive V1 # 1 dive1 0.5790946 # 2 dive2 0.4864489 库未设计为split-apply-combine作为其主要焦点。相反,它使用两部分融化/施法策略来执行m a wide variety of data reshaping tasks。但是,由于它允许聚合功能,因此可以用于此问题。它不是我拆分应用组合操作的首选,但它的重塑功能非常强大,因此您也应该学习这个包。

reshape2

基准

10行,2组

library(reshape2)
dcast( melt(df), variable ~ dive, mean)
# Using dive as id variables
#   variable     dive1     dive2
# 1    speed 0.5790946 0.4864489

benchmark 10 rows

像往常一样,library(microbenchmark) m1 <- microbenchmark( by( df$speed, df$dive, mean), aggregate( speed ~ dive, df, mean ), splitmean(df), ddply( df, .(dive), function(x) mean(x$speed) ), dcast( melt(df), variable ~ dive, mean), dt[, mean(speed), by = dive], summarize( group_by(df, dive), m = mean(speed) ), summarize( group_by(dt, dive), m = mean(speed) ) ) > print(m1, signif = 3) Unit: microseconds expr min lq mean median uq max neval cld by(df$speed, df$dive, mean) 302 325 343.9 342 362 396 100 b aggregate(speed ~ dive, df, mean) 904 966 1012.1 1020 1060 1130 100 e splitmean(df) 191 206 249.9 220 232 1670 100 a ddply(df, .(dive), function(x) mean(x$speed)) 1220 1310 1358.1 1340 1380 2740 100 f dcast(melt(df), variable ~ dive, mean) 2150 2330 2440.7 2430 2490 4010 100 h dt[, mean(speed), by = dive] 599 629 667.1 659 704 771 100 c summarize(group_by(df, dive), m = mean(speed)) 663 710 774.6 744 782 2140 100 d summarize(group_by(dt, dive), m = mean(speed)) 1860 1960 2051.0 2020 2090 3430 100 g autoplot(m1) 有更多的开销,因此小数据集的平均值大约相同。然而,这些是微秒,所以差异是微不足道的。任何方法在这里都可以正常工作,你应该根据:

进行选择
  • 您已经熟悉或想要熟悉的内容(data.table总是值得学习它的灵活性;如果您计划分析大量数据集,plyr值得学习; {{ 1}}和data.tableby都是基本R函数,因此可以普遍使用)
  • 它返回什么输出(numeric,data.frame或data.table - 后者继承自data.frame)

1000万行,10组

但是如果我们有一个大数据集怎么办?让我们尝试分成10组的10 ^ 7行。

aggregate

benchmark 1e7 rows, 10 groups

然后splitdf <- data.frame(dive=factor(sample(letters[1:10],10^7,replace=TRUE)),speed=runif(10^7)) dt <- data.table(df) setkey(dt,dive) m2 <- microbenchmark( by( df$speed, df$dive, mean), aggregate( speed ~ dive, df, mean ), splitmean(df), ddply( df, .(dive), function(x) mean(x$speed) ), dcast( melt(df), variable ~ dive, mean), dt[,mean(speed),by=dive], times=2 ) > print(m2, signif = 3) Unit: milliseconds expr min lq mean median uq max neval cld by(df$speed, df$dive, mean) 720 770 799.1 791 816 958 100 d aggregate(speed ~ dive, df, mean) 10900 11000 11027.0 11000 11100 11300 100 h splitmean(df) 974 1040 1074.1 1060 1100 1280 100 e ddply(df, .(dive), function(x) mean(x$speed)) 1050 1080 1110.4 1100 1130 1260 100 f dcast(melt(df), variable ~ dive, mean) 2360 2450 2492.8 2490 2520 2620 100 g dt[, mean(speed), by = dive] 119 120 126.2 120 122 212 100 a summarize(group_by(df, dive), m = mean(speed)) 517 521 531.0 522 532 620 100 c summarize(group_by(dt, dive), m = mean(speed)) 154 155 174.0 156 189 321 100 b autoplot(m2) 使用data.table操作显然是可行的方法。某些方法(dplyrdata.table)开始看起来很慢。

1000万行,1,000组

如果你有更多的团体,差异就会变得更加明显。 1,000组和相同的10 ^ 7行:

aggregate

enter image description here

所以dcast继续扩展,df <- data.frame(dive=factor(sample(seq(1000),10^7,replace=TRUE)),speed=runif(10^7)) dt <- data.table(df) setkey(dt,dive) # then run the same microbenchmark as above print(m3, signif = 3) Unit: milliseconds expr min lq mean median uq max neval cld by(df$speed, df$dive, mean) 776 791 816.2 810 828 925 100 b aggregate(speed ~ dive, df, mean) 11200 11400 11460.2 11400 11500 12000 100 f splitmean(df) 5940 6450 7562.4 7470 8370 11200 100 e ddply(df, .(dive), function(x) mean(x$speed)) 1220 1250 1279.1 1280 1300 1440 100 c dcast(melt(df), variable ~ dive, mean) 2110 2190 2267.8 2250 2290 2750 100 d dt[, mean(speed), by = dive] 110 111 113.5 111 113 143 100 a summarize(group_by(df, dive), m = mean(speed)) 625 630 637.1 633 644 701 100 b summarize(group_by(dt, dive), m = mean(speed)) 129 130 137.3 131 142 213 100 a autoplot(m3) data.table进行操作也很有效,dplyr data.table接近一个数量级。 dplyr / data.frame策略似乎在群组数量上表现不佳(意味着split可能很慢而sapply很快)。 split()仍然相对有效 - 在5秒内,它对用户来说肯定是显而易见的,但对于数据集来说,这个大的数据集仍然不合理。尽管如此,如果您经常处理此大小的数据集,sapply显然是可行的方法 - 100%data.table以获得最佳效果,by使用data.table dplyr作为一种可行的替代方案。

答案 1 :(得分:6)

aggregate(speed~dive,data=df,FUN=mean)
   dive     speed
1 dive1 0.7059729
2 dive2 0.5473777

答案 2 :(得分:4)

使用dplyr进行2015年更新:

df %>% group_by(dive) %>% summarise(percentage = mean(speed))
Source: local data frame [2 x 2]

   dive percentage
1 dive1  0.4777462
2 dive2  0.6726483

答案 3 :(得分:0)

我们已经有很多选择可以按组别平均,mosaic包中又增加了一个。

mosaic::mean(speed~dive, data = df)
#dive1 dive2 
#0.579 0.440 

这将返回一个命名的数值向量,如果需要一个数据框,我们可以将其包装在stack

stack(mosaic::mean(speed~dive, data = df))

#  values   ind
#1  0.579 dive1
#2  0.440 dive2

数据

set.seed(123)
df <- data.frame(dive=factor(sample(c("dive1","dive2"),10,replace=TRUE)),
                 speed=runif(10))

答案 4 :(得分:0)

添加了可选的基本R方法,该方法在各种情况下均保持快速。

rowsummean <- function(df) {
  rowsum(df$speed, df$dive) / tabulate(df$dive)
}

从@Ari借用基准测试:

10行2组

res1

1000万行,10组

res2

1000万行,1000个组

res3

答案 5 :(得分:0)

使用 collapse

library(collapse)
library(magrittr)
df %>% 
   fgroup_by(dive) %>%
   fsummarise(speed = fmean(speed))
#   dive     speed
#1 dive1 0.5788479
#2 dive2 0.4401514

数据

set.seed(123)
df <- data.frame(dive=factor(sample(c("dive1","dive2"),10,replace=TRUE)),
             speed=runif(10))