使用apply函数来平均数据帧组

时间:2015-09-08 20:23:27

标签: r

我的数据框:

df<-data.frame(ID = rep(c("no","bo", "fo", "to"), each = 3), matrix(sample(60), ncol = 5))
names(df) <- c("ID", letters[1:5])

我计算了每个观察组的平均值,我使用了这个:

 df.n.mean <- aggregate(. ~ ID, df, function(x) c(mean = mean(x)))

我想知道我是否可以使用apply方法而不是聚合方法。这会加快这个过程吗?

2 个答案:

答案 0 :(得分:3)

我认为aggregate()的最快替代是使用 data.table

library(data.table)
( dt <- setDT(df)[, lapply(.SD, mean), by = ID] )
#    ID         a        b        c        d        e
# 1: no 25.000000 26.00000 24.66667 39.00000 39.66667
# 2: bo 40.666667 25.33333 31.33333 37.00000 19.33333
# 3: fo  5.333333 28.00000 53.33333 11.66667 29.33333
# 4: to 30.666667 47.33333 27.00000 41.33333 28.00000

对于行减法,我们可以编写一个函数并将其与Map()一起使用。

f <- function(x, y) {
    dt[ID == x, -1, with = FALSE] - dt[ID == y, -1, with = FALSE]
}
rbindlist(Map(f, c("bo", "fo", "to", "to"), c("no", "no", "bo", "fo")))
#            a          b          c          d          e
# 1:  15.66667 -0.6666667   6.666667  -2.000000 -20.333333
# 2: -19.66667  2.0000000  28.666667 -27.333333 -10.333333
# 3: -10.00000 22.0000000  -4.333333   4.333333   8.666667
# 4:  25.33333 19.3333333 -26.333333  29.666667  -1.333333

可能有更好的方法来编写函数f()以及 data.table 中的最后一次调用,如果可能的话,我会尝试改进它。请注意,由于您在未设置种子的情况下使用sample(),此输出将与您的输出不匹配。

另一种可能性是做以下事情。这将为您提供所需的行名称。

A <- c("bo", "fo", "to", "to")
B <- c("no", "no", "bo", "fo")
df2 <- as.data.frame(rbindlist(Map(f, A, B)))
rownames(df2) <- paste(A, B, sep = "-")
df2
#               a          b          c          d          e
# bo-no  15.66667 -0.6666667   6.666667  -2.000000 -20.333333
# fo-no -19.66667  2.0000000  28.666667 -27.333333 -10.333333
# to-bo -10.00000 22.0000000  -4.333333   4.333333   8.666667
# to-fo  25.33333 19.3333333 -26.333333  29.666667  -1.333333

答案 1 :(得分:2)

您可以使用包dplyr和函数summarise_each来替换aggregate

library(dplyr)
newdf <- df %>% group_by(ID) %>% summarise_each(funs(mean))

给你

      ID        a        b        c        d        e
  (fctr)    (dbl)    (dbl)    (dbl)    (dbl)    (dbl)
1     bo 48.66667 32.00000 22.66667 33.33333 33.33333
2     fo 19.33333 15.00000 36.66667 25.33333 23.00000
3     no 35.00000 22.33333 37.00000 20.66667 31.00000
4     to 41.33333 39.00000 20.33333 37.00000 37.00000

这个包通常很快。但是,我不确定你问题的第二部分是否符合理查德的建议。