r-wakalangでそんな話があった時のメモ。もっといいコードがある気もしつつ、まあこれが割とシンプルなのではないでしょうか。問題は、purrrの使い方をいざという時に思い出せないというだけで。。(重大)
plyr::mdply()
私はポストplyr世代なのでplyrまったく分からないのですが、この関数がやりたいことに近いみたいです。(実は違うけど)
plyr::mdply(data.frame(mean = 1:5, sd = 1:5), rnorm, n = 2) #> mean sd V1 V2 #> 1 1 1 0.1394717 -1.233116 #> 2 2 2 3.4665594 5.460578 #> 3 3 3 1.2068706 2.323817 #> 4 4 4 4.4370674 8.491732 #> 5 5 5 4.5515510 14.603859
dplyrのIssuesを検索
mdply、でdplyrのIssuesを検索すると、gridExtraの人がそれっぽい機能要望を挙げてました。
で、最後にHadleyがこう書いてます。
This now feels more like a job for purrr.
出ました、purrr。
purrr::by_slice()
ということで、purrrを見てみると、それっぽいのがありました。slice_rows()
はdplyrでいうgroup_by
的なもので、by_slice()
はsummarise()
とかdo()
にあたるものです。
違うのは、.collate
という引数があることです。これに"rows"
を指定すると行として、"cols"
を指定すると列として、"list"
はリストとして、それぞれ結果が追加されます。
library(purrr) iris %>% slice_rows("Species") %>% by_slice(~ quantile(.$Sepal.Length), .collate = "cols") #> Source: local data frame [3 x 6] #> #> Species .out1 .out2 .out3 .out4 .out5 #> <fctr> <dbl> <dbl> <dbl> <dbl> <dbl> #> 1 setosa 4.3 4.800 5.0 5.2 5.8 #> 2 versicolor 4.9 5.600 5.9 6.3 7.0 #> 3 virginica 4.9 6.225 6.5 6.9 7.9
個人的には
purrrの.collate
引数は便利なので、いつも思うんですけどtidyrにもつけてほしいです。
もし↓こんな風に書ければ、list()
でラップするのが不格好ですが、個人的には分かりやすい気がします。。
iris %>% group_by(Species) %>% summarize(sepal_length_quantile = list(quantile(Sepal.Length))) %>% tidyr::unnest(sepal_length_quantile, .collate = "cols")