Jak przekazać nazwaną listę do argumentu kropek (`…`) funkcji (konkretnie `anova`) w R? (alternatywa dla `do.call`)

Dec 15 2020

Mam listę wyjściowych modeli mieszanych, lme4::lmerktóre chcę przekazać, do anovaktórej ma postać anova(object, ...), więc robię

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

Otrzymuję wynik, ale z nazwami rodzajowymi wymienionymi w ostrzeżeniu, a więc ten sam wynik, jakby models_listnie został nazwany. Pytałem też na githubie (https://github.com/lme4/lme4/issues/612), ale użycie do.callwydaje się, że nie będę w stanie rozwiązać tego problemu. Czy jest jakiś inny sposób?

Powtarzalny przykład

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

tak nazwami modeli fm1, fm2zostały zastąpione MODEL2, MODEL1; jest to problem, jeśli nazwy modeli są podawane poprzez zmianę (prawdopodobnie nie kolejnych) numerów.

Sprawdziłem możliwe pytania, których byłyby one swego rodzaju duplikatem, jak np

  • Jak przekazać listę do funkcji w R?
  • Przekaż częściową listę argumentów do do.call ()
  • Jak przekazać dodatkowy argument do argumentu funkcji funkcji do.call w języku R

ale nie znalazłem zadowalającej odpowiedzi.

Dziękuję Ci!

Odpowiedzi

2 Roland Dec 15 2020 at 18:50

anova.merModużywa niestandardowej oceny (NSE), aby uzyskać nazwy modeli. Jak to często bywa, NSE przysparza więcej kłopotów niż jest tego warte. Oto rozwiązanie:

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

Rozwiązanie tworzy połączenie. Odbywa się to z callfunkcją jak zwykle. Jednak tutaj musimy przekazać (w cudzysłowie) argumenty jako listę za pomocą do.call. Następnie oceniamy to wezwanie w ramach listy modeli.

Chciałbym uniknąć tego w kodzie produkcyjnym, ponieważ jest dość złożony i dlatego trudny w utrzymaniu.