R 简化多个一对一的聚合

R 简化多个一对一的聚合,r,split,aggregate,melt,R,Split,Aggregate,Melt,我想计算多个一对一聚合的平均值。例如,我在下面有一个data.frame。我想通过sym和a1计算列b1的平均值,同时通过sym和a2计算列b2的平均值 sym a1 a2 b1 b2 1 a 1 2 1 1 2 a 2 2 2 2 3 a 1 2 3 3 4 a 2 2 4 4 5 b 1 1 5 5 6 b 2 1 6 6 7 b 1 1 7 7 8 b 2 1 8 8 下面是我的代码,它

我想计算多个一对一聚合的平均值。例如,我在下面有一个data.frame。我想通过
sym
a1
计算列
b1
的平均值,同时通过
sym
a2
计算列
b2
的平均值

   sym a1 a2 b1 b2
1   a  1  2  1  1
2   a  2  2  2  2
3   a  1  2  3  3
4   a  2  2  4  4
5   b  1  1  5  5
6   b  2  1  6  6
7   b  1  1  7  7
8   b  2  1  8  8
下面是我的代码,它使用
lappy
对每一对进行迭代。还有比这更有效的方法吗

df <- data.frame(sym=c(rep('a', 4), rep('b', 4)), a1=rep(1:2, 4), 
                 a2=rep(2:1, each=4), b1=rep(1:8), b2=rep(1:8))

tmp <- ddply(df, "sym", function(x) {

  temp.ls <- lapply(1:2, function(i) {
    t2 <- aggregate(x = x[3+i], by=x[1+i], FUN=function(.){mean(., na.rm = T)})
    colnames(t2) <- c("a", "b")
    t2
  })
  temp.all <- Reduce(function(x, y) merge(x, y, by=c("a"), all=T, sort=T), 
                     temp.ls)
})

df
dplyr
使这一点非常简单:

library(dplyr)
inner_join(df %>% group_by(sym, a1) %>% summarise(b1.mean=mean(b1)),
           df %>% group_by(sym, a2) %>% summarise(b2.mean=mean(b2)))

# Joining by: "sym"
# Source: local data frame [4 x 5]
# Groups: sym
# 
#   sym a1 b1.mean a2 b2.mean
# 1   a  1       2  2     2.5
# 2   a  2       3  2     2.5
# 3   b  1       6  1     6.5
# 4   b  2       7  1     6.5
如果您想为
a
创建一个列,并想像示例解决方案中那样用
NA
填充不出现的组合,则
左键联接
是一个选项:

left_join(df %>% group_by(sym, a=a1) %>% summarise(b1.mean=mean(b1)),
          df %>% group_by(sym, a=a2) %>% summarise(b2.mean=mean(b2)),
          by=c('sym', 'a'))

# Source: local data frame [4 x 4]
# Groups: sym
# 
#   sym a b1.mean b2.mean
# 1   a 1       2      NA
# 2   a 2       3     2.5
# 3   b 1       6     6.5
# 4   b 2       7      NA
@初学者提醒我关于
dplyr
join
操作的提示


编辑

作为对注释的响应,如果您有两个以上的分组,并且希望将所有生成的表连接在一起,那么有一种方法可以做到这一点:

# Example data
set.seed(1)
(d <- data.frame(sym=sample(letters[1:4], 10, replace=T),
           a1=sample(5, 10, replace=TRUE),
           a2=sample(5, 10, replace=TRUE),
           a3=sample(5, 10, replace=TRUE),
           b1=runif(10), b2=runif(10), b3=runif(10)))

#    sym a1 a2 a3        b1         b2         b3
# 1    b  2  5  3 0.8209463 0.47761962 0.91287592
# 2    b  1  2  3 0.6470602 0.86120948 0.29360337
# 3    c  4  4  3 0.7829328 0.43809711 0.45906573
# 4    d  2  1  1 0.5530363 0.24479728 0.33239467
# 5    a  4  2  5 0.5297196 0.07067905 0.65087047
# 6    d  3  2  4 0.7893562 0.09946616 0.25801678
# 7    d  4  1  4 0.0233312 0.31627171 0.47854525
# 8    c  5  2  1 0.4772301 0.51863426 0.76631067
# 9    c  2  5  4 0.7323137 0.66200508 0.08424691
# 10   a  4  2  3 0.6927316 0.40683019 0.87532133

L <- mapply(function(x, y) {
    grpd <- eval(substitute(group_by(d, sym, a=x), list(x=as.name(x))))
    eval(substitute(summarise(grpd, mean(y)), list(y=as.name(y))))
}, paste0('a', 1:3), paste0('b', 1:3), SIMPLIFY=FALSE)

Reduce(function(...) left_join(..., all=T), L)

# Source: local data frame [9 x 5]
# Groups: sym
# 
#   sym a  mean(b1)   mean(b2)   mean(b3)
# 1   a 4 0.6112256         NA         NA
# 2   b 1 0.6470602         NA         NA
# 3   b 2 0.8209463 0.86120948         NA
# 4   c 2 0.7323137 0.51863426         NA
# 5   c 4 0.7829328 0.43809711 0.08424691
# 6   c 5 0.4772301 0.66200508         NA
# 7   d 2 0.5530363 0.09946616         NA
# 8   d 3 0.7893562         NA         NA
# 9   d 4 0.0233312         NA 0.36828101
#示例数据
种子(1)

(d Good point@初学者-我已经将其纳入了答案中。我注意到,在我发布前29秒的评论中,您提出了基本相同的解决方案-抱歉!很好!我喜欢这种方法。+1:)我感谢这个看起来非常好的解决方案。是否可以将组_中的列动态引用为,例如[i]。另外,我想加入以上10个结果。有可能吗?@YYY-你可以做一些事情,比如:
x@jbaums再次感谢你的回复。我的意思是我有a1-a20和b1-b20。是否会有几个左撇子将20个结果合并在一起?