[R] データフレームをグルーピングして、sum,max 〜by関数編

2018年4月23日月曜日

R

SQLのgroup byのようにRのデータフレームをグルーピングして、sumやmaxを取るのに意外に手間取ってしまったので、メモ。

まず、データ

このようにA,B,Cとラベリングされたデータに対して、ラベルの値ごとにsumやmaxを取りたい。
label <- c("A", "B", "C", "A", "B", "C")
v1 <- c(1, 2, 3, 4, 5, 6)
v2 <- c(100, 200, 300, 400, 500, 600)
df <- data.frame(label, v1, v2)
df
   label v1  v2
 1     A  1 100
 2     B  2 200
 3     C  3 300
 4     A  4 400
 5     B  5 500
 6     C  6 600

by関数とcolSums関数

単純にsumを取りたい場合は、colSums関数をby関数に渡せばいい。
by関数の第一引数は関数を適用したいデータフレーム、第二引数はグルーピングしたいキーのリスト、第三引数はグルーピン後のサブデータフレームに適用したい関数となる。
by(df[,2:3], df$label, colSums)
 df$label: A
  v1  v2 
   5 500 
 ------------------------------ 
 df$label: B
  v1  v2 
   7 700 
 ------------------------------ 
 df$label: C
  v1  v2 
   9 900 

maxはどうする。

by関数とcolSums関数でグループ毎のsumは取れるけど、maxは適用する関数をもう少し一般形にする必要がある。
具体的には適用する関数を無名関数で作ってあげればいい。
by(df, df$label, function(m) c(v1 = max(m$v1), v2 = max(m$v2)))
 df$label: A
  v1  v2 
   4 400 
 ------------------------------- 
 df$label: B
  v1  v2 
   5 500 
 ------------------------------- 
 df$label: C
  v1  v2 
   6 600 

これで、グループ毎のmaxが取れるし、無名関数の中でデータのカラムを選別するので、by関数の第一引数をサブデータフレームにする必要もない。

同じ考え方で、colSumsを使わずにsumを取ると、以下のようになる。
by(df, df$label, function(m) c(v1 = sum(m$v1), v2 = sum(m$v2)))
 df$label: A
  v1  v2 
   5 500 
 ------------------------------- 
 df$label: B
  v1  v2 
   7 700 
 ------------------------------- 
 df$label: C
  v1  v2 
   9 900