vapplyとtapplyの使い方について

この記事はRstudioのSwirlの「11: vapplyとtapply」を参照しています。
まずFlagsというデータセットをRに読み込みます(Swirlを使用している場合、自動的に読み込まれます。)。
参考までにflagsのsummaryの結果を示します。

> summary(flags)
             name        landmass          zone            area        
 Afghanistan   :  1   Min.   :1.000   Min.   :1.000   Min.   :    0.0  
 Albania       :  1   1st Qu.:3.000   1st Qu.:1.000   1st Qu.:    9.0  
 Algeria       :  1   Median :4.000   Median :2.000   Median :  111.0  
 American-Samoa:  1   Mean   :3.572   Mean   :2.211   Mean   :  700.0  
 Andorra       :  1   3rd Qu.:5.000   3rd Qu.:4.000   3rd Qu.:  471.2  
 Angola        :  1   Max.   :6.000   Max.   :4.000   Max.   :22402.0  
 (Other)       :188                                                    
   population         language        religion          bars       
 Min.   :   0.00   Min.   : 1.00   Min.   :0.000   Min.   :0.0000  
 1st Qu.:   0.00   1st Qu.: 2.00   1st Qu.:1.000   1st Qu.:0.0000  
 Median :   4.00   Median : 6.00   Median :1.000   Median :0.0000  
 Mean   :  23.27   Mean   : 5.34   Mean   :2.191   Mean   :0.4536  
 3rd Qu.:  14.00   3rd Qu.: 9.00   3rd Qu.:4.000   3rd Qu.:0.0000  
 Max.   :1008.00   Max.   :10.00   Max.   :7.000   Max.   :5.0000  
                                                                   
    stripes          colours           red             green       
 Min.   : 0.000   Min.   :1.000   Min.   :0.0000   Min.   :0.0000  
 1st Qu.: 0.000   1st Qu.:3.000   1st Qu.:1.0000   1st Qu.:0.0000  
 Median : 0.000   Median :3.000   Median :1.0000   Median :0.0000  
 Mean   : 1.552   Mean   :3.464   Mean   :0.7887   Mean   :0.4691  
 3rd Qu.: 3.000   3rd Qu.:4.000   3rd Qu.:1.0000   3rd Qu.:1.0000  
 Max.   :14.000   Max.   :8.000   Max.   :1.0000   Max.   :1.0000  
                                                                   
      blue             gold            white            black      
 Min.   :0.0000   Min.   :0.0000   Min.   :0.0000   Min.   :0.000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:1.0000   1st Qu.:0.000  
 Median :1.0000   Median :0.0000   Median :1.0000   Median :0.000  
 Mean   :0.5103   Mean   :0.4691   Mean   :0.7526   Mean   :0.268  
 3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:1.000  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.0000   Max.   :1.000  
                                                                   
     orange         mainhue      circles          crosses      
 Min.   :0.000   red    :71   Min.   :0.0000   Min.   :0.0000  
 1st Qu.:0.000   blue   :40   1st Qu.:0.0000   1st Qu.:0.0000  
 Median :0.000   green  :31   Median :0.0000   Median :0.0000  
 Mean   :0.134   white  :22   Mean   :0.1701   Mean   :0.1495  
 3rd Qu.:0.000   gold   :19   3rd Qu.:0.0000   3rd Qu.:0.0000  
 Max.   :1.000   black  : 5   Max.   :4.0000   Max.   :2.0000  
                 (Other): 6                                    
    saltires          quarters         sunstars         crescent     
 Min.   :0.00000   Min.   :0.0000   Min.   : 0.000   Min.   :0.0000  
 1st Qu.:0.00000   1st Qu.:0.0000   1st Qu.: 0.000   1st Qu.:0.0000  
 Median :0.00000   Median :0.0000   Median : 0.000   Median :0.0000  
 Mean   :0.09278   Mean   :0.1495   Mean   : 1.387   Mean   :0.0567  
 3rd Qu.:0.00000   3rd Qu.:0.0000   3rd Qu.: 1.000   3rd Qu.:0.0000  
 Max.   :1.00000   Max.   :4.0000   Max.   :50.000   Max.   :1.0000  
                                                                     
    triangle           icon           animate           text        
 Min.   :0.0000   Min.   :0.0000   Min.   :0.000   Min.   :0.00000  
 1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:0.000   1st Qu.:0.00000  
 Median :0.0000   Median :0.0000   Median :0.000   Median :0.00000  
 Mean   :0.1392   Mean   :0.2526   Mean   :0.201   Mean   :0.08247  
 3rd Qu.:0.0000   3rd Qu.:0.7500   3rd Qu.:0.000   3rd Qu.:0.00000  
 Max.   :1.0000   Max.   :1.0000   Max.   :1.000   Max.   :1.00000  
                                                                    
   topleft      botright 
 black :12   red    :69  
 blue  :43   blue   :47  
 gold  : 6   green  :40  
 green :32   white  :17  
 orange: 4   black  : 9  
 red   :56   gold   : 9  
 white :41   (Other): 3  
vapply

前回の記事で以下のコードを実行すると、結果としてリストを返すことが分かりました
(それぞれのリストの要素の長さが異なるため、簡潔化(simplify)できずlapplyと同じ結果となります。)

> sapply(flags, unique)

ここで、もしunique関数の機能を忘れていて、ダブりを除いた結果を数値(numeric)で返すと認識していたらどうなるでしょうか。その場合コードの途中で間違いが起こってしまいます。そのような間違いを防ぐために、vapplyの出番となります。sapplyが結果のフォーマットをRがある程度予測するするのに対し、vapplyでは結果のフォーマットを自分で指定することができます。それにより、予期しない結果を得ることを防ぐことができます。
以下のコードは結果はnumericで長さ1を返すよう指定しています。コードを実行するとどうなるでしょうか。

> vapply(flags, unique, numeric(1))

結果はこのようになり、エラーが発生します。

Error in vapply(flags, unique, numeric(1)) : values must be length 1,
 but FUN(X[[1]]) result is length 194

例えば前回の記事で行った以下のコードを実行するとsapplyはキャラクターベクターを結果として返します。

> sapply(flags, class)

この結果をもとに、vapplyで以下のコードを実行するとsapplyと同じ結果を返します。これはvapplyにclass関数をflagsのそれぞれの列に実行し、結果はcharacterで長さ1と指定しているからです。

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

このようにvapplyを使用することで予期せぬエラーを防ぐことができますが、コードの動作をその都度確認している場合にはsapplyで十分です。

tapply

データを処理する際、データをある変数を基にグループで分け、その分割されたグループに対し、ある計算を行いたいことがあります。tapplyはまさにそのようなことを行います。何を言っているのかわかりずらいと思いますので、例を見ていきましょう。

flagsデータのlandmassは1から6の整数の値を取り、それにより世界の異なる地域を表します。

> table(flags$landmass)

 1  2  3  4  5  6 
31 17 35 52 39 20 

同様にflagsデータのanimateは、もしその国旗が何かキャラクター(鷲、木、人の手など)を含んでいる場合は1を、含んでいない場合は0となります。

> table(flags$animate)

  0   1 
155  39 

この結果より、39の国旗が何かしらのキャラクターを含んでいることが分かります。もしこの平均値を取ると、全体の国旗に対するキャラクターを含んでいる国旗の割合を計算できます。下の結果から20%の国旗で何かしらのキャラクターを含んでいることが分かります。

> 39/194*100
[1] 20.10309

以上を基に、以下のコードを実行してみましょう。

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

これはどういう意味かというと、それぞれのlandmassグループ1から6に対し、animateの平均値(mean)を求めています。landmass=1は北アメリカ大陸を表し、42%の国旗がキャラクターを含んでいます。
また以下の例では、国旗に赤色を含んでいる又はいない国の人口(100万)の概要を示しています。

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

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

国旗に赤色を含んでいない国の人口の中央値は3.00であることが分かります。