我有一个类似于此的大型数据框:
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
的每个值。
答案 0 :(得分:95)
在R中有很多方法可以做到这一点。具体来说,by
,aggregate
,split
和plyr
,cast
,{{1} },tapply
,data.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 page对dplyr
所说的内容:
已经可以使用
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
library(reshape2)
dcast( melt(df), variable ~ dive, mean)
# Using dive as id variables
# variable dive1 dive2
# 1 speed 0.5790946 0.4864489
像往常一样,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.table
和by
都是基本R函数,因此可以普遍使用)但是如果我们有一个大数据集怎么办?让我们尝试分成10组的10 ^ 7行。
aggregate
然后split
或df <- 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
操作显然是可行的方法。某些方法(dplyr
和data.table
)开始看起来很慢。
如果你有更多的团体,差异就会变得更加明显。 1,000组和相同的10 ^ 7行:
aggregate
所以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组
1000万行,10组
1000万行,1000个组
答案 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))