R 分组计算平均数

R 分组计算平均数,r,dataframe,r-faq,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

我有一个大数据框,看起来像这样:

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
df
潜水速度
1第1部分0.80668490
2第1部分0.53349584
3第2部分0.07571784
4第2部分0.39518628
5第1部分0.84557955
6第1部分0.69121443
7第1部分0.38124950
8第2部分0.22536126
9第1部分0.04704750
10第2部分0.93561651

我的目标是当另一列等于某个值时,获得一列中值的平均值,并对所有值重复此操作。i、 e.在上面的示例中,我想返回
速度
的每个唯一值的平均值
下降
。因此,当
dive==dive1
时,
speed
的平均值为
dive
的每一个值,以此类推,在R中有很多方法可以做到这一点。具体地说,
通过
聚合
拆分
,和
plyr
转换
塔普利
数据。表
,等等

aggregate(speed~dive,data=df,FUN=mean)
   dive     speed
1 dive1 0.7059729
2 dive2 0.5473777
从广义上讲,这些问题的形式是分裂-应用-合并。Hadley Wickham写了一篇文章,可以让你更深入地了解整个问题类别,这篇文章非常值得一读。他的
plyr
包实现了通用数据结构的策略,而
dplyr
是针对数据帧调整的较新实现性能。它们允许解决相同形式的问题,但比这个问题更复杂。作为解决数据操作问题的通用工具,它们非常值得学习

在非常大的数据集上,性能是一个问题,因此很难找到基于
data.table
的解决方案。但是,如果您只处理中型或小型数据集,那么花时间学习
data.table
可能不值得
dplyr也可以很快,因此如果您想加快速度,但不太需要
data.table的可伸缩性,那么它是一个不错的选择

下面的许多其他解决方案不需要任何附加包。其中一些在中大型数据集上的速度甚至相当快。他们的主要缺点要么是隐喻,要么是灵活性。我所说的隐喻是指,它是一种工具,是为被强迫以“聪明”的方式解决这类特殊问题而设计的。我所说的灵活性,是指他们缺乏解决范围如此广泛的类似问题的能力,或者缺乏轻松产生整洁输出的能力


例子
base
函数
tapply

tapply(df$speed, df$dive, mean)
#     dive1     dive2 
# 0.5419921 0.5103974
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
聚合

library(data.table)
setDT(df)[ , .(mean_speed = mean(speed)), by = dive]
#    dive mean_speed
# 1: dive1  0.5419921
# 2: dive2  0.5103974
library(dplyr)
group_by(df, dive) %>% summarize(m = mean(speed))
aggregate
接收data.frames,输出data.frames,并使用公式接口

aggregate( speed ~ dive, df, mean )
#    dive     speed
# 1 dive1 0.5790946
# 2 dive2 0.4864489
作者

library(data.table)
setDT(df)[ , .(mean_speed = mean(speed)), by = dive]
#    dive mean_speed
# 1: dive1  0.5419921
# 2: dive2  0.5103974
library(dplyr)
group_by(df, dive) %>% summarize(m = mean(speed))
它以最用户友好的形式接受向量并对其应用函数。但是,它的输出不是一种非常可操作的形式:

res.by <- by(df$speed, df$dive, mean)
res.by
# df$dive: dive1
# [1] 0.5790946
# ---------------------------------------
# df$dive: dive2
# [1] 0.4864489
拆分

library(data.table)
setDT(df)[ , .(mean_speed = mean(speed)), by = dive]
#    dive mean_speed
# 1: dive1  0.5419921
# 2: dive2  0.5103974
library(dplyr)
group_by(df, dive) %>% summarize(m = mean(speed))
顾名思义,它只执行拆分应用联合收割机策略的“拆分”部分。为了使其余的工作正常,我将编写一个小函数,它使用apply combine的
sapply
<代码>sapply
自动尽可能简化结果。在我们的例子中,这意味着一个向量而不是一个data.frame,因为我们只有一维的结果

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

library(data.table)
setDT(df)[ , .(mean_speed = mean(speed)), by = dive]
#    dive mean_speed
# 1: dive1  0.5419921
# 2: dive2  0.5103974
library(dplyr)
group_by(df, dive) %>% summarize(m = mean(speed))
plyr
(dplyr
的前光标)

以下是关于plyr的
plyr

使用
base
R函数(如
split
apply
函数系列),但是
plyr
使这一切变得更容易 与:

  • 完全一致的名称、参数和输出
  • 通过
    foreach
    包方便地进行并行化
  • 数据的输入和输出。帧、矩阵和列表
  • 用于跟踪长期运行操作的进度条
  • 内置的错误恢复和信息性错误消息
  • 在所有转换中维护的标签
换句话说,如果您学习了一种用于拆分应用联合收割机操作的工具,那么它应该是
plyr

library(plyr)
res.plyr <- ddply( df, .(dive), function(x) mean(x$speed) )
res.plyr
#    dive        V1
# 1 dive1 0.5790946
# 2 dive2 0.4864489

基准 10行,2组

然后使用对数据进行操作的
data.table
dplyr
。某些方法(
aggregate
dcast
)开始显得非常缓慢

1000万行,1000组 如果有更多的组,则差异会更明显。1000组和相同的10^7行:

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)

df2015年使用dplyr更新:

tapply(df$speed, df$dive, mean)
#     dive1     dive2 
# 0.5419921 0.5103974
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

我们已经有大量的选项可供选择,从
mosaic
包中再添加一个选项

mosaic::mean(speed~dive, data = df)
#dive1 dive2 
#0.579 0.440 
这将返回一个命名的数字向量,如果需要一个数据帧,我们可以将其包装在
堆栈中

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))
set.seed(123)

df添加替代的base R方法,在各种情况下保持快速

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

rowsummean使用
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哇…非常感谢这是一个巨大的帮助。聚合函数工作得很好,微基准库对于我的绘图非常适合。再次感谢!此外,
microbenchmark
软件包对事物进行了基准测试。这是
ggplot2
,它实际上在那里制作了一个绘图(这是一个很棒的包)。+10好的,很好。这更像是有1000个小组。非常感谢你补充这一点。我将在接下来的两周内休假,这样你就可以从我的窃听中好好休息一下,听到:-)@Gregor nice你会松一口气的!非常感谢。看起来很漂亮,而且早就该更新dplyr了。显示带有/不带有
数据的
dplyr
。表
。真是太棒了。这是一个多么优秀、精确、全面的答案啊。荣誉。关于如何拆分应用合并但保留结果的相关问题