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

実際のコード

最も単純にパイプを表現すると以下の式になると思います。 普通に読むと'%>%'は引数にafをとって、 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 とかくと 「あぁafに入れてgに入れたのか」と分かります。

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

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

"$"(iris,Species)

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

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

iris %>% "$"(Species)

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

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

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

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