R Cheat Sheet (11): vapply and tapply

本文通过实例说明R语言*apply()系列中vapply()和tapply()的用法,所用到的数据同R语言中lapply()和sapply()的用法。在http://archive.ics.uci.edu/ml/machine-learning-databases/flags/flag.data下载到flag.data文件,将其导入R:

names <- c("name", "landmass", "zone", "area", "population", "language", "religion",
           "bars", "stripes", "colours", "red", "green", "blue", "gold", "white", 
           "black", "orange", "mainhue", "circles", "crosses", "saltires", "quarters",
           "sunstars", "crescent", "triangle", "icon", "animate", "text", "topleft",
           "botright")

flags <- read.csv("flag.data", col.names=names)

1. vapply()

R语言入门(10): lapply and sapply中说明了sapply()的用法,sapply()会尝试对apply的结果进行简化,如果无法简化,则不进行简化,返回原始结果。与sapply()类似,vapply()也会对apply结果进行简化,vapply()的不同之处在于,它需要显式地指明所希望简化为的具体格式,如果无法简化为所指定的格式,则会给出Error。使用cls_vect <- sapply(flags, class) 可以得到flags中各列的类型名称,并简化为一个character型的vector,使用vapply()并指明结果格式为character(1) 可以得到相同的结果:

> vapply(flags, class, character(1))
      name   landmass       zone       area population   language   religion       bars 
  "factor"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
   stripes    colours        red      green       blue       gold      white      black 
 "integer"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
    orange    mainhue    circles    crosses   saltires   quarters   sunstars   crescent 
 "integer"   "factor"  "integer"  "integer"  "integer"  "integer"  "integer"  "integer" 
  triangle       icon    animate       text    topleft   botright 
 "integer"  "integer"  "integer"  "integer"   "factor"   "factor"

 而如果希望通过vapplu()得到numeric(1) 的结果,会出现Error:

> vapply(flags, class, numeric(1))
Error in vapply(flags, class, numeric(1)) : values must be type 'double',
 but FUN(X[[1]]) result is type 'character'

通过显式指明所希望得到的格式,vapply()比sapply()更加“保险”,你总能通过vapply()得到希望的结果(或者Error)。此外,在大量数据下使用vapply()的效率要比sapply()高,因为vapply()不需要像sapply()那样去猜测如何对结果进行合适的简化。

2. tapply()

tapply()允许根据某些变量的值,把原始数据分割为若干组,然后对每一组数据应用特定的操作。在flags数据中,landmass表示国家所在的洲(1=N.America, 2=S.America, 3=Europe, 4=Africa, 4=Asia, 6=Oceania ),animate为1时表示国旗中包含卡通动画形象(如鹰、树等),反之为0。查看landmass和animate各个取值所包含的数据条数如下:

> table(flags$landmass)

 1  2  3  4  5  6 
31 17 35 52 38 20 
>
> table(flags$animate)

  0   1 
154  39

如果想要知道在各个洲国家中,国旗上有卡通动画形象所占的比例,则可以使用:

> tapply(flags$animate, flags$landmass, mean)
        1         2         3         4         5         6 
0.4193548 0.1764706 0.1142857 0.1346154 0.1538462 0.3000000

这里tapply(flags$animate, flags$landmass, mean) 表示将flags$animate的数据按照flags$landmass的值进行分组,然后对各组应用mean()计算均值。这里flags$landmass共可取1到6之间的六个整数值,根据flags$landmass的不同取值,flags$animate被分为6组。flags$animate取值为0或1,对其求均值,即为flags$animate中1(国旗上有卡通动画形象)所占的比例。

类似地,可以这样根据国旗上是否有红色,来分别统计这两类国家的人口情况:

> tapply(flags$population, flags$red, summary)
${{EJS0}}
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00    0.00    3.00   27.63    9.00  684.00 

${{EJS1}}
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    0.0     0.0     4.0    22.1    15.0  1008.0