Rでデータをカテゴリ別に集計(足し上げや平均など)したいときに使える関数には tapply
やby
、stats::aggregate
があります。 ここではまずtapply
についてご紹介します。
使用するデータ
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
を使うのがおすすめです。 Type
とTreatment
をまとめるとこうなります。
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の方を先に持っています。
$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
を使った集計についてのご紹介でした。