Rではライブラリmagrittrをロードしてパイプ演算子(%>%)を使うことにより、コードの可読性を高めることができます。ここではパイプ演算子の使い方について整理します。
パイプ演算子( %>% )
パイプ演算子を使うことで左辺の結果を右辺の第一引数にすることができます。これを活用することにより、計算結果を順次、左から右に流すようにコードを記述することができます。以下に計算例を示します。
以下の計算を行います。
① x = 1, 2, 3, … ,10 、 y = 10, 9, 8 ,… ,1 となるdata.frameの作成
② そのうち、x > 5となる行のみ選択
③ 選択したデータのx, yそれぞれに対して平均を計算
下記に示す計算1〜3はすべて同じ計算をしています。
library(magrittr)
library(dplyr)
# 計算1
df1 <- data.frame(x = 1:10, y = 10 :1)
df2 <- filter(df1, x > 5)
sapply(df2, mean)
# 計算2
sapply(filter(data.frame(x = 1:10, y = 10:1), x > 5), mean)
# 計算3
data.frame(x = 1:10, y = 10:1) %>%
filter(x > 5) %>%
sapply(mean)
> # 計算1
> df1 <- data.frame(x = 1:10, y = 10 :1)
> df2 <- filter(df1, x > 5)
> sapply(df2, mean)
x y
8 3
>
> # 計算2
> sapply(filter(data.frame(x = 1:10, y = 10:1), x > 5), mean)
x y
8 3
>
> # 計算3
> data.frame(x = 1:10, y = 10:1) %>%
+ filter(x > 5) %>%
+ sapply(mean)
x y
8 3
計算1は各ステップの計算結果をそれぞれ変数として保持しています。一応、計算の中身を追えるようにdf1, df2の内容を示してみると以下のようになっています。この書き方は計算の流れを追ったり、途中経過を確認できるという点では良いのですが、暫定的な変数df1, df2を作らねばなりません。他の場所でdf1, df2が使われているとデータを上書きしてしまうので、事前にdf1, df2を使うことが問題ないか確認しなければいけません。
> df1
x y
1 1 10
2 2 9
3 3 8
4 4 7
5 5 6
6 6 5
7 7 4
8 8 3
9 9 2
10 10 1
> df2
x y
1 6 5
2 7 4
3 8 3
4 9 2
5 10 1
計算2は計算の途中過程を変数に代入しないで、関数呼び出しに直接書く形でコーディングしています。計算がネスト状になるため、コードの可読性が非常に悪くなっています(計算2の結果を再掲しておきます)。
> # 計算2
> sapply(filter(data.frame(x = 1:10, y = 10:1), x > 5), mean)
x y
8 3
計算3はパイプ演算子%>%を使って書いたものです。パイプ演算子を使うことによって、左から右に計算のステップが追える形でコードを書くことができ、非常にわかりやすくなっています(計算3の結果を再掲しておきます)。
> # 計算3
> data.frame(x = 1:10, y = 10:1) %>%
+ filter(x > 5) %>%
+ sapply(mean)
x y
8 3
ドット演算子(.)
パイプ演算子を使うことで、左辺の結果を右辺の第一引数にすることができます。でも、もし、左辺の結果を第一引数以外の引数に対して、渡したい場合はどうしたらよいでしょうか?そのための仕組みがドット演算子(.)です。ドット(.)が左辺の結果を意味します。
下の計算例では、計算3, 4で左辺の結果(この場合はv1そのももの)を右辺の第二引数に渡しています。
myfunc <- function(x, y){ # x, y の中身をprintすだけの関数
print(paste0("x = ",x))
print(paste0("y = ",y))
}
v1 <- 1
v5 <- 5
v1 %>% myfunc(v1) # 計算1 : x = v1(パイプ演算子) , y = v1
v1 %>% myfunc(v5) # 計算2 : x = v1(パイプ演算子) , y = v5
v1 %>% myfunc(x = v1, y = .) # 計算3 : x = v1 , y = v1(パイプ&ドット演算子)
v1 %>% myfunc(x = v5, y = .) # 計算4 : x = v5 , y = v1(パイプ&ドット演算子)
> v1 %>% myfunc(v1) # 計算1 : x = v1(パイプ演算子) , y = v1
[1] "x = 1"
[1] "y = 1"
> v1 %>% myfunc(v5) # 計算2 : x = v1(パイプ演算子) , y = v5
[1] "x = 1"
[1] "y = 5"
> v1 %>% myfunc(x = v1, y = .) # 計算3 : x = v1 , y = v1(パイプ&ドット演算子)
[1] "x = 1"
[1] "y = 1"
> v1 %>% myfunc(x = v5, y = .) # 計算4 : x = v5 , y = v1(パイプ&ドット演算子)
[1] "x = 5"
[1] "y = 1"
パイプ演算子を使うと、「〇〇して、〜〜して、××する」みたいな一連の流れが途切れず書けるようになります。一度これに慣れてしまうと離れられない。とっても便利なので、いたるところで大活躍です。
まとめ
- ライブラリmagrittrをロードすることでパイプ演算子を使うことができる。
- パイプ演算子(%>%)は左辺の結果を次の処理の第一引数に渡すことができる。
- ドット演算子(.)を使うことで、左辺の結果を第一引数以外の引数に渡すこともできる。