Hatena::ブログ(Diary)

盆栽日記

2014-10-27

dplyrのなんたら_eachを効率的に使う

正直誰でも知ってる関数だし他にも解説している記事はあるので今さらだが、dplyrパッケージのなんたら_each関数の使い方をまとめる。

なんたら_eachを知ることでコピペを連発していたうちの同僚は感動のあまり涙の海に沈んだ。

たとえば以下のように一つの列に対して複数の操作を加えたいことがある。

iris %>% group_by(Species) %>% summarise(MIN=min(Sepal.Length),
                                  MEAN=mean(Sepal.Length),
                                  MEDIAN=median(Sepal.Length),
                                  MAX=max(Sepal.Length)
                                  )

1つの列ならまだいいが、これが複数の列になると心が闇に染まる。

iris %>% group_by(Species) %>% summarise(MIN_SL=min(Sepal.Length),
                                         MEAN_SL=mean(Sepal.Length),
                                         MEDIAN_SL=median(Sepal.Length),
                                         MAX_SL=max(Sepal.Length),
                                         MIN_SW=min(Sepal.Width),
                                         MEAN_SW=mean(Sepal.Width),
                                         MEDIAN_SW=median(Sepal.Width),
                                         MAX_SW=max(Sepal.Width)
                                         )

列名を書き換えるだけで心が折れる

さて、これをsummarise_eachを使うことで簡潔に書ける。

iris %>% group_by(Species) %>% summarise_each(funs(min, mean, median, max), Sepal.Length, Sepal.Width)

summarise_eachの第一引数に適用したい関数をfunsでくるんで入れたあと、適用する列名を続ければ良い。

ちなみに今回適用する列名は全てSepalという文字列で始まっており、irisデータの他の列名にSepalで始まる列は無い。

したがって、さらにstarts_with関数を用いて以下のように書き直せる。

iris %>% group_by(Species) %>% summarise_each(funs(min, mean, median, max), starts_with("Sepal"))

starts_with関数のような関数は他にもあるので以下にまとめた。

なお、以下の関数群はselect関数、summarise_each関数、mutate_each関数の中でしか使えないので注意。

関数例説明
starts_with(x, ignore.case=TRUE)xで始まる列名を取得。ignore.caseは文字の大小を無視するかどうか。
ends_with(x, ignore.case=TRUE)xで終わる列名を取得。
contains(x, ignore.case=TRUE)xを含む列名を取得。
matches(x, ignore.case=TRUE)正規表現xに対応する列名を取得。
num_range("x", 1:5, width=2)文字列と数値の組み合わせで列名を取得。widthは頭に0をつけた場合の桁数。この場合x01からx05を取得
one_of("x","y","z")"x","y","z"のうちどれか一つにでも該当する列名を取得。
everything全ての列を取得。

matches使って列名取得してやればだいぶ楽になるのではないだろうか。キモチイイイイイイイイイイイイイ!!!!!!!!

ぜひ使って使用感を教えてほしい。

余談

さて、余談だが通常以下のように列名を文字列で指定するとエラーになる。

iris %>% group_by(Species) %>% summarise_each(funs(min, mean, median, max), "Sepal.Width")

だが、以下のように書きかえることで動く。

iris %>% group_by(Species) %>% summarise_each_(funs(min, mean, median, max), "Sepal.Width")

違いがわかるだろうか?そう、summarise_eachの最後にアンダーバーを加えただけである。

dplyr 0.3になり、summarise_eachに限らずdplyrの基本関数(filter, select, summarise, mutate等)にはこのアンダーバーが加えられた関数が追加されている。

この違いはなにか。

この違いを理解するには作者のHadleyが最近はまってるNon Standard Evaluation(NSE)について知る必要があるが説明するの面倒なので誰かまとめてください。

追記(2014/10/28)

と思ったら、速効でkohskeさんがNSEについてまとめてくださいました!素敵!

http://qiita.com/kohske/items/7dbef6ae3ff34c093ce4

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

トラックバック - http://d.hatena.ne.jp/dichika/20141027/p1