R aov関数を分解する

Rでコンソールにaovと入力すると、関数の中身が現れる。普段あまり使わない関数も多数登場しているので、意味を確認することにする。

 

1

function (formula, data = NULL, projections = FALSE, qr = TRUE, contrasts = NULL, ...) 

"formula"は分散分析の対象変数を指定するもの、projectionsは推定を返すかどうか(何の推定?)、qrはQR分解を返すかどうか。contrastsも不明。保留。

 

2

{
    Terms <- if (missing(data)) {
  terms(formula, "Error")} else {
terms(formula, "Error", data = data)}

missing(data)は、引数dataが省略されていればTRUE、省略されていなければFALSEを返す。

termsはRの様々なデータオブジェクトから"terms"オブジェクトを取り出すための関数。ココによると、Rにはformulaクラスがあり、その中にtermsオブジェクトが格納されている。引数"Error"をつけることで、termsオブジェクトにattr("specials"),attr("specials")$Errorが追加される。

 

3

    indError <- attr(Terms, "specials")$Error 

上記で作成したTerms(termsオブジェクト)からattr("specials")$Errorを抽出し、indErrorに代入する。("Error"が何を表すのかは、要確認)

 

4

    if (length(indError) > 1L) {
stop(sprintf(ngettext(length(indError), "there are %d Error terms: only 1 is allowed", "there are %d Error terms: only 1 is allowed"), length(indError)), domain = NA)}

もしindErrorに2つ以上の値が格納されていれば、処理を中断し、エラーメッセージを表示する。

 

5

    lmcall <- Call <- match.call()
    lmcall[[1L]] <- as.name("lm")
    lmcall$singular.ok <- TRUE

match.call()関数は、RのヘルプのExampleを実行してみると、引数を記録する関数のようだ。引数のうち、最初の引き数(formulaか?)に"lm"という名前を付け、lmcall$sigular.okにTRUEを格納しておく。

 

6

    if (projections) {
        qr <- lmcall$qr <- TRUE}
    lmcall$projections <- NULL

projectionがTRUEであれば、lmcall$qrにTUREを格納し、それをqrとしておく。lmcall$projectionにNULLを格納しておく。

 

7

  if (is.null(indError)) {
    fit <- eval(lmcall, parent.frame())
    if (projections) 
      fit$projections <- proj(fit)
    class(fit) <- if (inherits(fit, "mlm")) 
      c("maov", "aov", oldClass(fit))
    else c("aov", oldClass(fit))
    fit$call <- Call
    return(fit)
  } #if節は次に続く

indErrorに何も値が格納されていない場合は、eval関数で文字列(今回ならlmcall)をRで実行する。5でlmcallはformulaが格納されていたから、それを実行して、fitに代入するという意味。parent.frame()はRのヘルプでevalを調べると、evalを実行する環境をしているもの(詳細要確認)。

 

8

#if節の続き
else { #is.null(indError)がFALSEの場合 if (pmatch("weights", names(match.call()), 0L)) stop("weights are not supported in a multistratum aov() fit") #if節はまだ続く

indErrorがNULLでない場合は、pmatch関数で引数match.call()のうち、"weights"に該当する引数が、引数match.call()のうち何番目にあるかを調べる。weightsがもしも無ければ、エラーを表示する。

 

9

#if節の続き
opcons <- options("contrasts") options(contrasts = c("contr.helmert", "contr.poly")) on.exit(options(opcons)) #if節はまだ続く

optionsはグローバルな(リセットしない限り常に有効な)オプションを設定する関数。Rのヘルプによると、contrastsはmodel fittingにおいて使われるオプションのことで、前者がunordered factorsに対して使われるもの、後者がordered factorsに対して使われるもの。"contr.helmert"は第2水準を第1水準と比較し、第3水準を第1水準と第2水準の平均と比較…するオプション。"contr.poly"は"直交多公式系"で比較を行うオプション。(詳細要確認)。on.exitはこの関数(aov関数)の実行後にオプションを保存しておく関数。

 

10

#if節の続き 
allTerms <- Terms errorterm <- attr(Terms, "variables")[[1 + indError]] eTerm <- deparse(errorterm[[2L]], width.cutoff = 500L, backtick = TRUE) intercept <- attr(Terms, "intercept") ecall <- lmcall
#if節はまだ続く

Termsは2で作成した通り、formulaのtermsオブジェクト。attr(Terms,"variables")はTermsの変数オブジェクトを表し、その[[1+indError]]番目をerrortermとする、という意味。deparseはwikiによると式を文字列に分解する関数。

atr(Terms,"intercept")はTermsの変数オブジェクト。lmcallはformulaに当たり、それをecallに代入する。

 

11

    ecall$formula <- as.formula(paste(deparse(formula[[2L]], width.cutoff = 500L, backtick = TRUE), "~", eTerm, if (!intercept)"- 1"), env = environment(formula))

ecallのformulaオブジェクトに、formula2~eTermを代入する。

 

【以下更新予定】

12

    ecall$method <- "qr"
    ecall$qr <- TRUE
    ecall$contrasts <- NULL
    er.fit <- eval(ecall, parent.frame())
    options(opcons)
    nmstrata <- attr(terms(er.fit), "term.labels")
    nmstrata <- sub("^`(.*)`$", "\\1", nmstrata)
    nmstrata <- c("(Intercept)", nmstrata)
    qr.e <- er.fit$qr
    rank.e <- er.fit$rank