Rを楽しむための道のりの一つには「中置関数と仲良くする」というステップがあると思います。多くの方が恩恵を受けているであろうtidyverseの中にある、中置関数の一つパイプ(%>%)に関し、以前こんな記事を書いてみたのですが、その頃よりちょっぴり書きたいネタが増えてしまいました。そこで今回は%>%を実際に作る過程を通じて中置関数を楽しんでもらいたいなと思います。

実際のコード

最も単純にパイプを表現すると以下の式になると思います。普通に読むと'%>%'は引数にaとfをとって、f(a)を返す関数だよ、と言っています。

'%>%' <- function (a,f) f(a)

ここでのミソは2つあります。1つは左辺、LHS(上の'%>%'側)の制約で、記号を%で挟むのが作法であるようです。そしてそれをクウォート('')してあげます。もう1つは項のとり方で、適用する際はfunction関数の第一引数を左にとり、第二引数を右に取ります。何を言っているんだ、という場合は次の例でスッキリするかもしれません。

iris %>% head
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa

上を見ると、確かに先ほど定義した中置関数(%>%)の左側にirisデータを置いて右側にhead関数を置くと、head(iris)の意味になることになります。

pipeの何が嬉しいのか

R界隈で今更(というと使っていない方に失礼ですが)pipeのありがたさを伝える意味はなさそうです。が、一応説明すると、以上の%>%を使うと関数の組み合わせの見通しが良くなります。まずデータaに対して関数fと関数gを適用するためにはg(f(a))とせねばなりません。しかし a %>% f %>% g とかくと「あぁaをfに入れてgに入れたのか」と分かります。

その他の中置関数の使い方

その便利さは語っても語りきれませんが、列にアクセスするdf$colも中置換数であることを思い出すと極めて稀に美味しいことがおきます。例えば$も中置関数なので、以下のように通常の呼び出し方ができます。

"$"(iris,Species)

これと先ほどの話を組み合わせてみます。先ほど作ったのは項を一つしかとらない関数に限定されているので、もっと柔軟な関数としてmagrittrパッケージの%>%を借ります。

library(magrittr)
# さっき作ったのは上書きする
"%>%" <- magrittr::"%>%"

iris %>% "$"(Species)

するとirisのSpecies列へアクセスできます。これが一体なんの役に立つかというと、パイプを切らせたくない時、です。データをガチャガチャしたあとで選択、とかだと、わけても可読性が上がるわけでもないのに加えて一時変数が増えるデメリットがあります。

iris %>% 長い操作 %>% "$"(Species)

あるいは apply系なんかにも中置関数使えますね!

mapply("*",c(1,2,3),c(1,2,3))
# 当然、以下だとエラーになる。
# mapply(*,c(1,2,3),c(1,2,3))
#  エラー:  予想外の '*' です  in "mapply(*"