モデル式を使えるようになりたい

lm()とかで使うチルダ使ったアレ.

lm(x ~ y, data = hoge)

モデル式,モデル公式,model fomulaなどと呼ぶ.すごくおおざっぱな言い方をすると,チルダ"~"の左側の変数を右側の式で説明するモデルを作成する*1

> str(x~y)
Class 'formula' length 3 x ~ y
  ..- attr(*, ".Environment")=<environment: R_GlobalEnv> 

クラスはformulaで,表現式オブジェクトみたく評価されてない状態のオブジェクトができる.
もうちっと詳しいことはやはりあそこ(Rの言語仕様とか色々参考にできそうな関数とかのメモ - yasuhisa's blog)を参考にしてもらうとして,やりたかったのは何かというとdata=というアレ.

my.dataframe <- data.frame(x=1:5, y=11:15)
plot(my.dataframe$x, my.dataframe$y)
plot(y~x, data=my.dataframe)

ここで挙げた二つのplotは同じ結果を与える*2が,後者の方が見やすいし入力しやすい.「yをxで説明する散布図を書いて,データはmy.dataframeに入ってるから」とそんなノリでplotできる.これはyやxがすぐ評価されないのでこういうことができている.
では評価はどうするのかということが問題になる.表現式ではないのでevalはダメ.要素に分解して$でくっつけてなんてのはなんだか面倒だし,モデル式という仕組みがあるんだからなんか方法があるハズ.とか思ってlm()の中身を眺めてた*3.それでどうもmodel.frame()というのがモデル式をデータフレームにするっぽい?とか思い始めたところ,まさにそのmodel.frame()の使い方を@phosphor_mがtwitterで教えてくれた.どうもありがとうございました.

要するにこんな感じ.

> x <- 1:5
> y <- 11:15
> z <- data.frame(x = 3:6, y= 4:7)
> model.frame(x~y)
  x  y
1 1 11
2 2 12
3 3 13
4 4 14
5 5 15
> model.frame(y~x, data=z)
  y x
1 4 3
2 5 4
3 6 5
4 7 6

また,交互作用とかそういうものを含めたモデル式でも特に計算は行われず(I()で括った場合は別),モデル式中の変数を左から順に並べたデータフレームが作られる.
自作関数でdata=という書き方を使いたかったらこのmodel.frame()を使えば簡単にできそう.

*1:演算子の働きが変わったりしてチルダの右辺は単純な式というわけじゃないんだけど

*2:実際にはラベルが違うし後者はplot.formulaで関数も違うんだけど

*3:ちなみに関数の動作を確認するにはdebug()が便利.debug(lm)などとして関数にフラグを立てた後にその関数を実行すると1実行文ずつ実行するモードになる.nかEnterで次の文,cで一気に終わらせる.