Rの関数(具体的には `anova`)のドット(`… `)引数に名前付きリストを渡す方法は?( `do.call`の代替)

Dec 15 2020

lme4::lmer渡したい混合モデルの出力のリストがanovaあり、その形式anova(object, ...)はです。

models_list <- list("lmm1" = lmm1, "lmm2" = lmm2, "lmm3" = lmm3, "lmm4" = lmm4, "lmm5" = lmm5)
do.call(anova, c(models_list[[1]], models_list[-1]))
Warning in anova.merMod(new("lmerMod", resp = new("lmerResp", .xData = <environment>),  :
  failed to find model names, assigning generic names

結果は得られますが、一般名が警告でmodels_list示されているため、名前が付けられていない場合と同じ結果になります。githubでも聞いてみました(https://github.com/lme4/lme4/issues/612)が、使用do.callするとこの問題を解決できないようです。他に方法はありますか?

再現可能な例

library(lme4)
fm1 <- lmer(Reaction ~ Days + (Days | Subject), sleepstudy)
fm2 <- lmer(Reaction ~ Days + (Days || Subject), sleepstudy)
anova(fm1,fm2)
refitting model(s) with ML (instead of REML)
Data: sleepstudy
Models:
fm2: Reaction ~ Days + ((1 | Subject) + (0 + Days | Subject))
fm1: Reaction ~ Days + (Days | Subject)
    npar    AIC    BIC  logLik deviance  Chisq Df Pr(>Chisq)
fm2    5 1762.0 1778.0 -876.00   1752.0                     
fm1    6 1763.9 1783.1 -875.97   1751.9 0.0639  1     0.8004
# so I can see fm2 and fm2, to which model corresponds each line, but
models_list <- list("fm1" = fm1, "fm2" = fm2)
do.call(anova, c(lmaux[[1]], lmaux[-1]))
Warning in anova.merMod(new("lmerMod", resp = new("lmerResp", .xData = <environment>),  :
  failed to find model names, assigning generic names
refitting model(s) with ML (instead of REML)
Data: sleepstudy
Models:
MODEL2: Reaction ~ Days + ((1 | Subject) + (0 + Days | Subject))
MODEL1: Reaction ~ Days + (Days | Subject)
       npar    AIC    BIC  logLik deviance  Chisq Df Pr(>Chisq)
MODEL2    5 1762.0 1778.0 -876.00   1752.0                     
MODEL1    6 1763.9 1783.1 -875.97   1751.9 0.0639  1     0.8004

モデル名のでfm1fm2置き換えられましたMODEL2MODEL1。これは、モデル名が(場合によっては連続していない)番号を変更して指定されている場合に問題になります。

私は、これらが一種の重複である可能性のある質問をチェックしました。

  • Rの関数にリストを渡す方法は?
  • 引数の部分的なリストをdo.call()に渡します
  • Rでdo.callの関数引数に追加の引数を渡す方法

しかし、満足のいく答えは見つかりませんでした。

ありがとうございました!

回答

2 Roland Dec 15 2020 at 18:50

anova.merMod非標準評価(NSE)を使用してモデル名を取得します。よくあることですが、NSEはその価値よりも厄介です。解決策は次のとおりです。

eval(
  do.call(
    call, 
    c(list("anova"), 
      lapply(names(models_list), as.symbol)), 
    quote = TRUE), 
  models_list)

#refitting model(s) with ML (instead of REML)
#Data: sleepstudy
#Models:
#fm2: Reaction ~ Days + ((1 | Subject) + (0 + Days | Subject))
#fm1: Reaction ~ Days + (Days | Subject)
#    npar    AIC    BIC  logLik deviance  Chisq Df Pr(>Chisq)
#fm2    5 1762.0 1778.0 -876.00   1752.0                     
#fm1    6 1763.9 1783.1 -875.97   1751.9 0.0639  1     0.8004

ソリューションは呼び出しを作成します。それはcallいつものように関数で行われます。ただし、ここでは、を使用して(引用符で囲まれた)引数をリストとして渡す必要がありdo.callます。次に、モデルのリスト内でこの呼び出しを評価します。

非常に複雑で保守が難しいため、本番コードでこれを使用しないようにします。