Rで集計に使える関数 - tapply

tapplyを使って個票データ(microdata)を足し上げよう。interactionの説明もあり
R
公開

2022年9月4日

Rでデータをカテゴリ別に集計(足し上げや平均など)したいときに使える関数には tapplybystats::aggregateがあります。 ここではまずtapplyについてご紹介します。

使用するデータ

datasets::CO2を例に使います。

head(datasets::CO2)
  Plant   Type  Treatment conc uptake
1   Qn1 Quebec nonchilled   95   16.0
2   Qn1 Quebec nonchilled  175   30.4
3   Qn1 Quebec nonchilled  250   34.8
4   Qn1 Quebec nonchilled  350   37.2
5   Qn1 Quebec nonchilled  500   35.3
6   Qn1 Quebec nonchilled  675   39.2

84データを持つdata frameで、最初の4列(Plant~conc)が実験環境、5列目(uptake)が結果数値です。 最初の4列のうち3列はfactor型ですが、concだけは数値型です。 factor型であることは後に表を整形するときなどに関わってきます。

tapply

tapplyを集計に使う場合に渡す引数は、

  • 1つ目に集計する値が入った列を指定
  • 2つ目に分類に使いたい列をListの形で指定
  • 3つ目に集計関数を指定(sumなら省略してもよい)

となります。

2つ目の引数がList型であるところがポイント。 列を1つしか指定しないときでもListにしないといけないのでちょっと煩わしいですが、実は列を2つ以上渡すことも可能なのでList型である必要があります。

1つ目に結果数値のuptake、2つ目に分類としてTypeを指定してみましょう。

tapply(CO2$uptake, CO2["Type"], sum)
Type
     Quebec Mississippi 
     1408.8       877.1 

Type列の値ごとにuptakeを足し上げた結果を得られました。

分類を2つに増やすと、2次元の表が得られます。

tapply(CO2$uptake, CO2[c("Type", "conc")], sum) # 2次元の表
             conc
Type            95   175   250   350   500   675 1000
  Quebec      84.4 162.5 215.6 228.5 228.8 237.0  252
  Mississippi 62.7 104.9 130.9 139.5 141.7 146.4  151

3つにすると3次元の表が得られますが、ベタに表示するとちょっと読みにくいですね。

tapply(CO2$uptake, CO2[c("Type", "conc", "Treatment")], sum) # 3次元の表
, , Treatment = nonchilled

             conc
Type            95  175   250   350   500   675  1000
  Quebec      45.8 90.1 112.2 121.1 118.8 124.5 129.5
  Mississippi 33.9 60.6  82.6  89.7  91.8  91.6  94.8

, , Treatment = chilled

             conc
Type            95  175   250   350   500   675  1000
  Quebec      38.6 72.4 103.4 107.4 110.0 112.5 122.5
  Mississippi 28.8 44.3  48.3  49.8  49.9  54.8  56.2

単に集計の結果をarrayに保持したいだけならこれでもいいですが、 視覚的に2次元にまとめて表示したいこともあります。 そういう場合は分類の変数をまとめてListの要素が2つに収まるようにするとよいでしょう。

interactionを使って変数を結合

変数をまとめるにはinteractionを使うのがおすすめです。 TypeTreatmentをまとめるとこうなります。

tapply(CO2$uptake, interaction(CO2$Type, CO2$Treatment), sum)
     Quebec.nonchilled Mississippi.nonchilled         Quebec.chilled    Mississippi.chilled 
                 742.0                  545.0                  666.8                  332.1 

interactionは、

  • 戻り値がList型
  • 渡した変数をfactor型に自動的に変換してくれる
  • factor型に変換されるときに組み合わせのすべてをlevelsに持つので、入力データに存在しない組み合わせも表示できる

という特徴があります。
今回の例では元からfactor型になっているので2点目、3点目は活用できていませんが、 1点目のList型で戻ってくるというだけでもtapplyの引数として使いやすくてよいですね。

「文字列として複数の変数をまとめるのはpasteじゃないの?」

という疑問をお持ちの方もいらっしゃると思います。 pasteでも同じことは可能です。こんな感じに書けます。

tapply(CO2$uptake, list(paste(CO2$Type, CO2$Treatment)), sum)
   Mississippi chilled Mississippi nonchilled         Quebec chilled      Quebec nonchilled 
                 332.1                  545.0                  666.8                  742.0 

同じ結果・・・ですが並び順が先ほどと違いますね。 pasteを使うと文字列の順番で並び替えて表示されます。確かにアルファベットではMississippiはQuebecよりも前です。 しかしTypeはもともとはfactor型で、Quebecの方を先に持っています。

attributes(CO2$Type)
$levels
[1] "Quebec"      "Mississippi"

$class
[1] "factor"

元データで何か意図があってlevelsを設定していることもありますので、その順番を保持するのが一般的にはよいと思います。

では、まとめた変数を使って先ほどの3次元の表を2次元に表示してみましょう。

tapply(CO2$uptake, cbind(interaction(CO2$Type, CO2$Treatment), CO2["conc"]), sum)
                                    conc
interaction(CO2$Type, CO2$Treatment)   95  175   250   350   500   675  1000
              Quebec.nonchilled      45.8 90.1 112.2 121.1 118.8 124.5 129.5
              Mississippi.nonchilled 33.9 60.6  82.6  89.7  91.8  91.6  94.8
              Quebec.chilled         38.6 72.4 103.4 107.4 110.0 112.5 122.5
              Mississippi.chilled    28.8 44.3  48.3  49.8  49.9  54.8  56.2

うまい具合に表示されました。

tappyを使った集計についてのご紹介でした。