¿Cómo pasar una lista con nombre al argumento de puntos (`...`) de una función (específicamente `anova`) en R? (alternativas a `do.call`)
Tengo una lista de salida de modelos mixtos de los lme4::lmer
que quiero pasar a los anova
que tienen el formulario anova(object, ...)
, así que lo hago
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
Obtengo el resultado, pero con los nombres genéricos señalados por la advertencia, por lo que el mismo resultado que si models_list
no tuviera un nombre. Pregunté también en github (https://github.com/lme4/lme4/issues/612), pero al usar do.call
parece que no podré resolver este problema. ¿Hay alguna otra manera?
Ejemplo reproducible
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 lo que los nombres de modelo fm1
, fm2
fueron reemplazados con MODEL2
, MODEL1
; esto es un problema si los nombres de los modelos se dan cambiando números (posiblemente no consecutivos).
He comprobado posibles preguntas de las cuales serían una especie de duplicado, como
- ¿Cómo pasar una lista a una función en R?
- Pasar lista parcial de argumentos a do.call ()
- Cómo pasar un argumento adicional al argumento de la función de do.call en R
pero no he encontrado ninguna respuesta satisfactoria.
¡Gracias!
Respuestas
anova.merMod
utiliza una evaluación no estándar (NSE) para obtener los nombres de los modelos. Como suele ser el caso, NSE es más problemático de lo que vale. He aquí una solución:
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
La solución crea una llamada. Eso se hace con la call
función como de costumbre. Sin embargo, aquí necesitamos pasar los argumentos (entre comillas) como una lista usando do.call
. Luego evaluamos esta llamada dentro de la lista de modelos.
Intentaría evitar tener esto en el código de producción porque es bastante complejo y, por lo tanto, difícil de mantener.