关于R当中的tapply

之前的博客《R数据分析当中的化整为零(Split-Apply-Combine)策略》有提到一些关于lapply, sapply, vapply的内容。对于tapply只是粗粗带过。

今天使用tapply的过程中遇到了一个非常令人困惑的问题,于是不得不仔细研究一下这个tapply。

tapply的使用很简单,当数据矩阵需要按其中的某一列,(或者几列,很少使用到)的内容来分组,在组内对数据需要使用指定的函数来运算时,就可以使用tapply。举个例子,有数据:

a<-data.frame(name=c("tom","sam","mik","ali"),age=c(8,9,8,9),score=c(50,100,70,90))
a
  name age score
1  tom   8    50
2  sam   9   100
3  mik   8    70
4  ali   9    90

如果我们需要按不同age来计算平均分的话,就可以使用到tapply.它的原型是,
tapply(X, INDEX, FUN = NULL, …, simplify = TRUE)

tapply(a[,"score"], a[,"age"], mean)
 8  9 
60 95

似乎很简单的东西。好了,我们现在把数据变换一下,

> a<-data.frame(name=c("sam","tom","ali","mik"),age=c(9,8,9,8),score=c(100,50,90,70))
> a
  name age score
1  sam   9   100
2  tom   8    50
3  ali   9    90
4  mik   8    70
> tapply(a[,"score"], a[,"age"], mean)
 8  9 
60 95

我们变换了数据的排序,但是在使用了tapply之后,它输出的结果还是与之前的一致。这一点非常有意思。这一点是否会导致一些潜在的错误呢?

我们还把数据变得更复杂一点。

> a<-data.frame(name=c("sam","tom","ali","mik"),age=c(9,8,9,8),math=c(100,50,90,70),verbal=c(90,60,96,80))
> a
  name age math verbal
1  sam   9  100     90
2  tom   8   50     60
3  ali   9   90     96
4  mik   8   70     80

我们现在需要对不同年龄段的成绩进行求平均,下面的写法是否正确呢?

> ages<-unique(a$age)
> ages
[1] 9 8
> b<-matrix(nrow=length(ages),ncol=2)
> rownames(b)<-ages
> colnames(b)<-c("math","verbal")
> for(i in 1:2){b[,i]<-tapply(a[,i+2],a[,"age"],mean)}

我们来看看结果是什么?

> b
  math verbal
9   60     70
8   95     93

其实很容易看出来,这里的rownames对应出现了错误。修改过来也很容易,

> ages<-levels(as.factor(a$age))
> ages
[1] "8" "9"
> rownames(b)<-ages
> b
  math verbal
8   60     70
9   95     93

这一看似很容易被识别的错误,但却很容易在大量数据处理时无法识别。就是因为对tapply没有理解透。tapply的排序方法是输入factor的levels

Leave a Reply

  

  

  

留言请必须回答: