jnobuyukiのブログ

研究していて困ったことやその解決に関するメモ。同じように困ったあなたのために。twitter ID: @j_nobuyuki

R言語でパイプ処理を利用してコードを見やすく

今回は、R言語のコードそのものを見やすくするという話です。

Rでのコードの書き方

R言語では、型を指定しないオブジェクトにデータやその下処理・解析結果を一時的に保持するのが典型的です。例えば以下のコードは、入力データ、下処理後データ、解析結果がそれぞれオブジェクトに保存されています。入力データは、下処理にかけられ、その結果が別のオブジェクトとして保存されます。その結果が、解析にとっての入力になり、さらに結果のオブジェクトが保存されるという流れです。

#入力データ
input <- data.frame(x = rnorm(100), y = rnorm(100))
#下処理
subdata <- subset(input,x > 0)
#解析
result <- lm(y ~ x, data = subdata)

#結果の表示
summary(result)

上記のコードは、一時的な結果を保持するオブジェクトが利用されています。メモリを節約するために、なるべく一時的な保持のオブジェクトを作らないように書くと、次のようになります。

summary(lm(y ~ x, data = subset(data.frame(x = rnorm(100),y = rnorm(100)),x>0)))

確かにメモリは節約できているかもしれませんが、この書き方は関数が複雑な入れ子になっていて、コードが読みにくいものになっています。このように標準的なコードでは、メモリの管理もしくは読みにくさがトレードオフの関係になってしまいがちです。

パイプ処理による解決

上記の問題の解決手段の一つがパイプ処理です。今回は、magrittrというパッケージを利用して、より読みやすいコードの書き方をまとめます*1。なお、magrittrなどのパイプ処理を実現するパッケージの解説記事は、以下がおすすめです。

www.amazon.co.jp

%>%

%>%というパイプ処理では、パイプの左側の結果を、パイプ右側に配置した関数の最初の引数に割り当てます。または、明示的に.で割り当て位置を決定することもできます。試みに上記のコードをパイプ処理を利用して書いてみましょう。

library(magrittr)

input <- data.frame(x = rnorm(100),y = rnorm(100)) %>% subset(x >0) %>% lm(y ~ x, data = .) %>% summary

このように書くとinputとして作成したデータがsubset関数、lm関数、summary関数と順に処理されていく様子を容易に読み取れます。とても便利なのですが、1点注意するとしたら、これがbaseパッケージではできないことです。そのためmagrittrパッケージの導入に同意した人にしかコードをシェアできないということを忘れないようにしましょう。

*1:pipeRというパッケージもあるようです。