evalと仲良くなる

ベクトルがいくつかあったとします。例えばこんなの。

a1<-c(1,NA,3,4,5,1,4,9,9)
a2<-c(1,2,3,NA,5,6,7,3,9)
a3<-c(6,2,5,4,5,6,NA,8,9)
a4<-c(1,9,3,4,5,6,7,8,9)
a5<-c(3,2,3,4,5,6,7,8,9)
a6<-c(1,NA,3,4,5,6,7,1,9)
a7<-c(1,2,3,4,5,6,7,8,NA)
a8<-c(NA,2,3,4,5,6,7,8,9)
a9<-c(1,NA,3,4,5,6,7,2,9)
a10<-c(1,2,3,4,5,NA,7,8,9)

「a」の後に規則的に数字が並んでいて、それらのところどころには欠損値が含まれている。こいつらの欠損値の部分を0に書き換えたい。しかし、これらのベクトルは(本当は)たくさんある(とする)。繰り返し処理を使って簡単にできないだろうか…?というのが今日のお題。

a[1]とかいうデータならfor文ぶん回せばすぐ終わる。だけど、今回は変数名に数字とかが入ってる。どーしよー、ということになる。

で、evalが登場。evalは文字列をRの命令文として実行してくる、という機能を持つ。なので、for文を回して、変数名の数字がうまく出てくるような文字列を生成して、evalに渡してやればよい、ということになる。evalの公式は

eval(parse(text="文字列"))

となっている。これを使って、欠損値になっているところに0を代入していく処理を書いてみる。

for(i in 1:10){
  eval(
       parse(
             text=paste(
               "a",i,"[is.na(a",i,")]<-0",sep=""
               )
             )
       )
}

欠損値がなくなったかどうかを見るのもevalを使って書いてみる。

for(i in 1:10){
  eval(
       parse(
             text=paste(
               "print(a",i,")",sep=""
               )
             )
       )
}
[1] 1 0 3 4 5 1 4 9 9
[1] 1 2 3 0 5 6 7 3 9
[1] 6 2 5 4 5 6 0 8 9
[1] 1 9 3 4 5 6 7 8 9
[1] 3 2 3 4 5 6 7 8 9
[1] 1 0 3 4 5 6 7 1 9
[1] 1 2 3 4 5 6 7 8 0
[1] 0 2 3 4 5 6 7 8 9
[1] 1 0 3 4 5 6 7 2 9
[1] 1 2 3 4 5 0 7 8 9

欠損値が消えていることが分かる。

いや、まあPerlとか使って、全部のベクトル文のRのスクリプトを吐くプログラム書いてもいいんだけど。やっぱりRでやってみたいじゃないですか。

てか、こういう解き方はないものかとJavaで頑張ってた時期があった。R書いててそのやり方を知るとは。

追記
きしださんにtwitter経由でJavaでもできるということを教えてもらいました。

System.out.println(new ScriptEngineManager().getEngineByName("JavaScript").eval("23 * 44"));

JavaScriptのいろんなことが書けちゃうそうです。Javaすげぇ。きしださんすげぇ。

Rによるデータサイエンス-データ解析の基礎から最新手法まで

Rによるデータサイエンス-データ解析の基礎から最新手法まで