アメリエフの技術ブログ

Amelieff Staff Blog

(Rで)オブジェクトの名前を文字列として取り出す。関数内でも使える

今週のお題「納豆」

納豆には、付属のつゆと生卵を混ぜていただくのが好きです。
美味しいし、ネバネバも薄まることで食べやすいので ★+1。

f:id:Fuku-I:20200710175820p:plain:w250

さて。こんにちはFukuです。


統計解析ソフト「R」で、オブジェクトの名前を文字列として取り出す方法を紹介します。

オブジェクト(変数)の名前って、ユーザにはもちろんわかるのですが、変数であるがゆえに代入されている中身を取り出すのは簡単で、逆に名前自体を呼び出すのがけっこう難しいのです。

## いろいろ試す
> mat
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    6   11   16   21
[2,]    2    7   12   17   22
[3,]    3    8   13   18   23
[4,]    4    9   14   19   24
[5,]    5   10   15   20   25
> as.character(mat)
 [1] "1"  "2"  "3"  "4"  "5"  "6"  "7"  "8"  "9"  "10" "11" "12" "13" "14" "15"
[16] "16" "17" "18" "19" "20" "21" "22" "23" "24" "25"
> names(mat)
NULL
> ls()
[1] "hoge"     "mat"       "matrix"    "my.data"
## できない(´・ω・`)

それを取り出す方法とは...こんなおまじない!

object_name <- as.character(eval(substitute(alist(...))))
> as.character(eval(substitute(alist(mat))))
[1] "mat"

mat というオブジェクト(変数)を入れると、"mat" と名前を出力させることができました。

かっこの中から順番に実行すると以下のようになりました。

> alist(mat)
[[1]]
mat   # 何やらリストになった

> substitute(alist(mat))
alist(mat)  # カッコの中がそのまま出てきた

> eval(substitute(alist(mat)))
[[1]]
mat   # 何やらリスト

> as.character(eval(substitute(alist(mat))))
[1] "mat"   # 文字列になった!  

関数に入れて

オブジェクトに対していろんな処理をして、オブジェクト名を冠したファイルを出力したい。この作業を自作関数にしたいとします。

こんなときは、変数の名前を文字列として取得することが必要ですね。
作成したコードの一部を紹介します。

myFunction <- function(...){
    x <- rownames(...)  
   # 中略。いろんな処理。
    output.data  <- cbind(..., x2)  # いろんな処理おわり
    object_name <- as.character(eval(substitute(alist(...))))  # 名前を取り出す  
    filename <- paste(object_name, "function.csv", sep=".")    # 出力ファイル名を作る  
    write.csv(output.data, filename)  # 書き出す
}

function() の中は、引数の名をxなどつけず、 ... にするとよさそうでした。

余談:おまじないを省略すると?

インテラクティブに使うだけなら、
省略して以下の方法でも目的の出力が得られました。

> as.character(substitute(mat))
[1] "mat"

しかし、自作の関数やループの中に入れると思い通りに動かないこともありました。ので、長いおまじないにはそれなりの理由があるものでしょう。

あとがき

長いおまじないを唱えないとできない処理なので、もしかしたらこのやり方をやりたい人がそもそも少ないのかもしれません。
でも、筆者と同じ思考回路でこれをやりたい人がいたら、お役に立てば幸いです!

参考

下のサイトを参考にしました。ありがとうございます。
オブジェクト名を生かしたlistを作る - Qiita