Como passar uma lista nomeada para o argumento de pontos (`…`) de uma função (especificamente `anova`) em R? (alternativas para `do.call`)
Eu tenho uma lista de saída de modelos mistos para os lme4::lmer
quais desejo passar e anova
que 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_list
não fosse nomeado. Eu perguntei também no github (https://github.com/lme4/lme4/issues/612), mas usando do.call
parece 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
, fm2
foram 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
anova.merMod
usa 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 call
funçã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.