expand.grid関数・outer関数を使って2重forループを美しく書く
twitterで「Rでfor文書いて本当にすまんかった」旨を呟いたら色々とアドバイスが貰えた。内容は「expand.grid関数やouter関数を使えばいいのではないか?」ということだったので、ちょっとメモがてらやっておく。
まずはexpand.grid関数を試してみると
> x.seq <- 1:3 > expand.grid(x.seq, x.seq) Var1 Var2 1 1 1 2 2 1 3 3 1 4 1 2 5 2 2 6 3 2 7 1 3 8 2 3 9 3 3 > > class(expand.grid(x.seq, x.seq)) [1] "data.frame"
というような結果を得られる。要するに2つのベクトルの要素の直積集合をデータフレーム型で返してくれるものらしい。マニュアルを見ると多次元でも行ける模様、便利便利。なんで
product <- c() for(i in x.seq){ for(j in x.seq){ product <- c(product,i*j) } } product
こんな2重forループと同じ動作をさせるには
apply(expand.grid(x.seq, x.seq), 1, prod)
と書けばいいわけだ。簡単簡単。
実行するとどちらも
> apply(expand.grid(x.seq, x.seq), 1, prod) [1] 1 2 3 2 4 6 3 6 9
を返してくる。
一方、outer関数は
> outer(x.seq, x.seq,function(x,y)x*y) [,1] [,2] [,3] [1,] 1 2 3 [2,] 2 4 6 [3,] 3 6 9
こんな風に計算結果を行列で返してくるので、先ほどの結果と同じにしたければas.numericを噛ませるようにして
> as.numeric(outer(x.seq, x.seq,function(x,y)x*y)) [1] 1 2 3 2 4 6 3 6 9
とすればいい。outer関数は2次元限定の模様なので汎用性という意味ではexpand.grid関数の勝ちかな?