gpt4 book ai didi

r - 按组计算平均值

转载 作者:行者123 更新时间:2023-12-03 05:56:02 26 4
gpt4 key购买 nike

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

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 的每个值是否如此等等.

最佳答案

在 R 中有很多方法可以做到这一点。具体来说,by , aggregate , split , 和 plyr , cast , tapply , data.table , dplyr ,等等。

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

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

下面的许多其他解决方案不需要任何额外的包。其中一些在中大型数据集上甚至相当快。它们的主要缺点是隐喻或灵活性之一。比喻我的意思是,它是一种工具,旨在以“聪明”的方式强制其他人解决这种特定类型的问题。我所说的灵活性是指他们缺乏解决范围广泛的类似问题或轻松产生整洁输出的能力。

例子
base职能

tapply :

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

aggregate :
aggregate接收data.frames,输出data.frames,并使用公式接口(interface)。
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

split :

顾名思义,它只执行拆分-应用-组合策略的“拆分”部分。为了让剩下的工作,我将编写一个使用 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

外包装

数据表 :
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 ( dplyr 的前体)

这是 official page不得不说 plyr :

It’s already possible to do this with base R functions (like split and the apply family of functions), but plyr makes it all a bit easier with:

  • totally consistent names, arguments and outputs
  • convenient parallelisation through the foreach package
  • input from and output to data.frames, matrices and lists
  • progress bars to keep track of long running operations
  • built-in error recovery, and informative error messages
  • labels that are maintained across all transformations


换句话说,如果您学习一种用于拆分-应用-组合操作的工具,它应该是 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

reshape2 :
reshape2库的设计重点不是拆分-应用-组合。相反,它使用两部分熔化/类型转换策略来执行 m a wide variety of data reshaping tasks .但是,由于它允许使用聚合函数,因此可以用于解决此问题。它不会是我对 split-apply-combine 操作的首选,但它的重塑能力非常强大,因此你也应该学习这个包。
library(reshape2)
dcast( melt(df), variable ~ dive, mean)
# Using dive as id variables
# variable dive1 dive2
# 1 speed 0.5790946 0.4864489

基准

10行,2组
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)

benchmark 10 rows

像往常一样, data.table有更多的开销,所以对于小数据集来说大约是平均的。但是,这些都是微秒,因此差异很小。任何方法在这里都可以正常工作,您应该根据以下情况进行选择:
  • 您已经熟悉或想要熟悉的内容(plyr 因其灵活性而始终值得学习;如果您打算分析庞大的数据集,data.table 值得学习;byaggregatesplit都是基本的 R 函数,因此普遍可用)
  • 它返回什么输出(数字、data.frame 或 data.table——后者继承自 data.frame)

  • 1000万行,10组

    但是如果我们有一个大数据集呢?让我们尝试将 10^7 行分成十个组。
    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)

    benchmark 1e7 rows, 10 groups

    然后 data.tabledplyrdata.table 上使用操作s 显然是要走的路。某些方法( aggregatedcast )开始看起来很慢。

    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)

    enter image description here

    所以 data.table继续很好地扩展,并且 dplyrdata.table 上操作也很好用, dplyrdata.frame慢了接近一个数量级。 split/ sapply策略似乎在组数量上的扩展性很差(意味着 split() 可能很慢,而 sapply 很快)。 by仍然相对高效——在 5 秒时,用户肯定会注意到这一点,但对于如此大的数据集来说,这仍然不是不合理的。尽管如此,如果您经常使用这种大小的数据集, data.table显然是要走的路 - 100% data.table 以获得最佳性能或 dplyrdplyr使用 data.table作为可行的替代方案。

    关于r - 按组计算平均值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11562656/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com