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

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

2022年9月4日

更新日

2025年6月8日

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型とヘルプには書かれていますが、実はListでなくただのvectorを渡しても勝手に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次元にまとめて表示したいこともあります。 そういう場合は分類の変数を次のようにまとめて要素が2つ以内に収まるようにするとよいでしょう。

interactionを使って変数を結合

2つ以上の変数を1つにまとめるには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は、

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

という特徴があります。

3点目はどういうことかと言うと、例えば分類の情報として次のようにA市-人口B市-面積C市-世帯数というデータがあったとします。

  city property
1  A市     人口
2  B市     面積
3  C市   世帯数

このデータの2つの分類をinteractionで1つにまとめると、A市に対して人口だけではなく面積世帯数もあるはずだとしてそれをfactor型のlevelsに入れてくれます。その結果、この例では9つのlevelsが作られます。

[1] A市.人口   B市.面積   C市.世帯数
Levels: A市.人口 B市.人口 C市.人口 A市.世帯数 B市.世帯数 C市.世帯数 A市.面積 B市.面積 C市.面積

これはデータが部分的に得られなかったときにそれをあえて表示したい場合などに役立ちます。

ちなみに1点目のとおりinteractionの戻り値はfactor型ですが、最初に述べたようにtapplyにはList型で渡さなくても勝手にListにしてくれますのでこのままtapplyの引数として使うことができます。

pasteを使うこともできる

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

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

tapply(CO2$uptake, 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型で、levelsとしてはQuebecの方を先に持っています。

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

$class
[1] "factor"

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

再びinteraction

では、まとめた変数を使って先ほどの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を使った集計についてのご紹介でした。