Como passar uma lista nomeada para o argumento de pontos (`…`) de uma função (especificamente `anova`) em R? (alternativas para `do.call`)

Dec 15 2020

Eu tenho uma lista de saída de modelos mistos para os lme4::lmerquais desejo passar e anovaque tem a forma anova(object, ...), então eu faço

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

Recebo o resultado, mas com os nomes genéricos assinalados pelo aviso, portanto, o mesmo resultado como se models_listnão fosse nomeado. Eu perguntei também no github (https://github.com/lme4/lme4/issues/612), mas usando do.callparece que não vou conseguir resolver esse problema. Existe alguma outra maneira?

Exemplo reproduzível

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

por isso os nomes dos modelos fm1, fm2foram substituídos por MODEL2, MODEL1; isso é um problema se os nomes dos modelos forem fornecidos por meio de números alterados (possivelmente não consecutivos).

Eu verifiquei possíveis perguntas das quais seriam uma espécie de duplicata, como

  • Como passar uma lista para uma função em R?
  • Passe uma lista parcial de argumentos para do.call ()
  • Como passar um argumento extra para o argumento da função de do.call em R

mas não encontrei nenhuma resposta satisfatória.

Obrigada!

Respostas

2 Roland Dec 15 2020 at 18:50

anova.merModusa avaliação não padrão (NSE) para obter os nomes dos modelos. Como costuma acontecer, o NSE é mais problemático do que vale a pena. Aqui está uma solução:

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

A solução cria uma chamada. Isso é feito com a callfunção normalmente. No entanto, aqui precisamos passar os argumentos (entre aspas) como uma lista usando do.call. Em seguida, avaliamos essa chamada dentro da lista de modelos.

Eu tentaria evitar isso no código de produção porque é bastante complexo e, portanto, difícil de manter.