niszetの日記

アナログCMOS系雑用エンジニアが頑張る備忘録系日記

(R) formulaをView()してみてみる(2回目)symbolの話も。

symbolはベクトルを作れない

既に下記の記事やっていた1のだが、 niszet.hatenablog.com

単純に、c()でベクトルを作ろうと思う。symbolas.symbol()で作る。

c(as.symbol("~"), as.symbol("a"))
[[1]]
`~`

[[2]]
a

構造を見てみると、

str(c(as.symbol("~"), as.symbol("a")))
#> List of 2
#>  $ : symbol ~
#>  $ : symbol a

is.list(c(as.symbol("~"), as.symbol("a")))
#> [1] TRUE

で、listになっている、と。ようやく理解できたかな…。

languageを直接作る方法はなさそう

さて、前回はformulaを分解してみていきました。

niszet.hatenablog.com

formulaはformula()as.formula()によって作ることができます。他にもa~bのような形で作れますが、後者の書式だとsymbolで書かねばならないので、文字列からas.formula()で作った方が関数等に使いまわしがしやすいかな。

rlangパッケージやplyrパッケージも見てみましたが、as.language()みたいな関数はなさそうです。が、

quote(a~b)
plyr::is.formula(quote(a~b))
#> [1] FALSE
is.language(quote(a~b))
#> [1] TRUE

quoteでlanguageとなります。この辺りはまた別にわけよう。

また、as.formula()の引数にあるように、formulaは環境(environment)を必要とします。前回見たように、languageenvironmentがついた構造がformulaです(class属性も持っているけど)

で、language~symbolで構成されて、1番目の要素は必ず~、そのあと左辺と右辺に相当するlanguagesymbolが入り、languageの場合は同じルールでネストすることが可能ということですね。前回見た通り。

ちなみに、

x<-as.formula("a~b")
x[[2]]<-as.formula("b~c")

で要素を置き換えることが出来るが、置き換えた部分はlanguageではなくformulaになってしまうのである。単体のlanguageオブジェクトを作って置き換える場合はquote()で。
あと、一旦formulaの形をとると、なんでも代入できる気がする。文字列"a~b"も関数sumも入った。View()で確認するとちゃんとそれぞれのオブジェクトのまま(languageとかsymbolにならないで)格納されていることがわかる。これはlanguageでも同じで、これはNSEにつながる話のようだな。

また、as.formula()にNULLを渡すとlistかつformulaとなるようだ。

x<-as.formula(NULL)
x
#> list()
is.list(x)
#> [1] TRUE
plyr::is.formula(x)
#> [1] TRUE

# 当然、通常の作り方の場合はlistではない。
is.list(a~b)
#> [1] FALSE
plyr::is.formula(x)
#> [1] TRUE

未評価のままオブジェクトを保存できる便利な箱の出来上がりですね。

symbolはシンボリックリンクみたいなもん。

symbolは変数の名前であって、中身は入っていないリンクのようなもので、リンク元を環境という形で与えられると値を取り出すことが出来る。

見た方が分かりやすくて、

a<- 1
x<-new.env()
x$a <- 1000
eval(as.symbol("a"))
#> [1] 1
eval(as.symbol("a"), envir = x)
#> [1] 1000

のように、適当な環境に変数aをその実体としては1であるように作っておくと、その環境のもとでeval()すればその環境での変数名から値を取り出すことが出来る、そんな感じ。

調べると調べた分だけ不明な点が出てくるので文章をまとめてから日記に出来ていませんが…。このあたり全容を把握出来たらもう一度清書したい…

Enjoy!!


  1. 教えていただいただけで僕何もしていないのでは。