Bagaimana cara meneruskan daftar bernama ke argumen titik (`…`) dari sebuah fungsi (khususnya `anova`) di R? (alternatif untuk `do.call`)

Dec 15 2020

Saya memiliki daftar keluaran model campuran lme4::lmeryang ingin saya sampaikan anovayang memiliki bentuk anova(object, ...), jadi saya lakukan

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

Saya mendapatkan hasilnya, tetapi dengan nama-nama generik yang ditandai dengan peringatan tersebut, jadi hasil yang sama seolah-olah models_listtidak disebutkan. Saya juga bertanya di github (https://github.com/lme4/lme4/issues/612), tetapi dengan menggunakan do.calltampaknya saya tidak dapat menyelesaikan masalah ini. Apakah ada cara lain?

Contoh yang dapat direproduksi

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

sehingga nama-nama model yang fm1, fm2digantikan dengan MODEL2, MODEL1; ini menjadi masalah jika nama model diberikan dengan mengubah nomor (kemungkinan tidak berurutan).

Saya telah memeriksa kemungkinan pertanyaan yang ini akan menjadi semacam duplikat, seperti

  • Bagaimana cara melewatkan daftar ke fungsi di R?
  • Meneruskan daftar sebagian dari argumen ke do.call ()
  • Cara meneruskan argumen ekstra ke argumen fungsi do.call di R

namun belum menemukan jawaban yang memuaskan.

Terima kasih!

Jawaban

2 Roland Dec 15 2020 at 18:50

anova.merModmenggunakan evaluasi non-standar (NSE) untuk mendapatkan nama model. Seperti yang sering terjadi, NSE lebih merepotkan daripada nilainya. Inilah solusinya:

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

Solusinya membuat panggilan. Itu dilakukan dengan callfungsi seperti biasa. Namun, di sini kita perlu meneruskan argumen (dikutip) sebagai daftar menggunakan do.call. Kami kemudian mengevaluasi panggilan ini dalam daftar model.

Saya akan mencoba menghindari ini dalam kode produksi karena cukup rumit dan karena itu sulit untuk dipelihara.