按因素计算分组的平均值

10
有没有一种方法可以改进这个,或者更简单地完成它?
means.by<-function(data,INDEX){
  b<-by(data,INDEX,function(d)apply(d,2,mean))
  return(structure(
    t(matrix(unlist(b),nrow=length(b[[1]]))),
      dimnames=list(names(b),col.names=names(b[[1]]))
  ))
}

这个想法与SAS MEANS BY语句相同。'means.by'函数接收一个数据框和一个索引变量,对于与INDEX唯一值对应的每组行,计算数据框列的平均值,并返回一个新的数据框,其中行名是INDEX的唯一值。

我确信在R中有更好的方法来做到这一点,但我想不出来。


我看到了你在网站上发布的示例。plyr正是为此功能而设计的。我已经更新了我的示例以匹配你网站上的输出。 - Brandon Bertelsen
4个回答

13

聚合函数是否符合您的要求?

如果不符合,可以看一下plyr包,它提供了几个选项来分解内容,对这些部分进行计算,然后再将其组合在一起。

您也可以尝试使用reshape包来完成此操作。


5
你需要使用tapplyave函数,具体取决于你想要的输出方式:
> Data <- data.frame(grp=sample(letters[1:3],20,TRUE),x=rnorm(20))
> ave(Data$x, Data$grp)
 [1] -0.3258590 -0.5009832 -0.5009832 -0.2136670 -0.3258590 -0.5009832
 [7] -0.3258590 -0.2136670 -0.3258590 -0.2136670 -0.3258590 -0.3258590
[13] -0.3258590 -0.5009832 -0.2136670 -0.5009832 -0.3258590 -0.2136670
[19] -0.5009832 -0.2136670
> tapply(Data$x, Data$grp, mean)
         a          b          c 
-0.5009832 -0.2136670 -0.3258590 

# Example with more than one column:
> Data <- data.frame(grp=sample(letters[1:3],20,TRUE),x=rnorm(20),y=runif(20))
> do.call(rbind,lapply(split(Data[,-1], Data[,1]), mean))
             x         y
a -0.675195494 0.4772696
b  0.270891403 0.5091359
c  0.002756666 0.4053922

这两个选项都不能满足我的需求,而且本质上是相同的。事实上,我正在使用的“by”函数只是tapply的一个包装器。我的想法是给定一个数据框,对列应用一个函数,并获得一个数据框或矩阵。 - Andrew Redd
我的错。我的示例只有一列。 - Joshua Ulrich

4

使用plyr

library(plyr)
df <- ddply(x, .(id),function(x) data.frame(
mean=mean(x$var)
))
print(df)

更新:

data<-data.frame(I=as.factor(rep(letters[1:10],each=3)),x=rnorm(30),y=rbinom(30,5,.5))
ddply(data,.(I), function(x) data.frame(x=mean(x$x), y=mean(x$y)))

注意,plyr 是很聪明的 :)

更新2:

根据您的评论,我相信来自reshape包的cast和melt更适合您的目的并且更简单。

cast(melt(data),I ~ variable, mean)

这个能适用于有100列的数据框吗?编写data.frame(x=mean(x$X),...)并不实际。我并不是要表现得消极或贬低,但这是我的情况背景,因此我正在寻找最好的解决方案,以便能够良好地扩展。 - Andrew Redd
答案是肯定的,你可以在ddply中使用整个函数。然而,我认为cast和melt更加高效地实现了这个目的。我已经更新了我的回答。 - Brandon Bertelsen

0

在R中只使用通用函数。

>d=data.frame(type=as.factor(rep(c("A","B","C"),each=3)),
x=rnorm(9),y=rgamma(9,2,1))
> d
type           x         y
1    A -1.18077326 3.1428680
2    A -0.91930418 4.4606603
3    A  0.88345422 1.0979301
4    B  0.06964133 1.1429911
5    B -1.15380345 2.7609049
6    B  1.13637202 0.6668986
7    C -1.12052765 1.7352306
8    C -1.34803630 2.3099202
9    C -2.23135374 0.7244689
>
> cbind(lm(x~-1+type,data=d)$coef,lm(y~-1+type,data=d)$coef)
         [,1]     [,2]
typeA -0.4055411 2.900486
typeB  0.0174033 1.523598
typeC -1.5666392 1.589873

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接