如何将命名列表传递给 R 中函数(特别是 anova)的点(`...`)参数? (替代 `do.call`)

How to pass a named list to the dots (`...`) argument of a function (specifically `anova`) in R? (alternatives to `do.call`)

我有一个 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; 如果模型名称是通过更改(可能是非连续的)数字给出的,则会出现问题。

我已经检查了可能存在重复的问题,因为

但一直没有找到满意的答案。

谢谢!

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 将(引用的)参数作为列表传递。然后我们在模型列表中评估此调用。

我会尽量避免在生产代码中使用它,因为它非常复杂,因此难以维护。