L'ottimizzatore lme4 predefinito richiede molte iterazioni per dati ad alta dimensione


12

TL; DR: l' lme4ottimizzazione sembra essere lineare nel numero di parametri del modello per impostazione predefinita ed è molto più lenta di un glmmodello equivalente con variabili fittizie per gruppi. C'è qualcosa che posso fare per accelerarlo?


Sto cercando di adattare un modello logit gerarchico abbastanza grande (~ 50k righe, 100 colonne, 50 gruppi). Adattare un modello logit normale ai dati (con variabili fittizie per gruppo) funziona bene, ma il modello gerarchico sembra bloccarsi: la prima fase di ottimizzazione si completa bene, ma la seconda attraversa molte iterazioni senza cambiare nulla e senza fermarsi .

EDIT: sospetto che il problema sia principalmente che ho così tanti parametri, perché quando provo a impostare maxfnun valore inferiore dà un avvertimento:

Warning message:
In commonArgs(par, fn, control, environment()) :
  maxfun < 10 * length(par)^2 is not recommended.

Tuttavia, le stime dei parametri non cambiano affatto nel corso dell'ottimizzazione, quindi sono ancora confuso su cosa fare. Quando ho provato a impostare maxfni controlli dell'ottimizzatore (nonostante l'avvertimento), mi è sembrato che si bloccasse dopo aver terminato l'ottimizzazione.

Ecco del codice che riproduce il problema per i dati casuali:

library(lme4)

set.seed(1)

SIZE <- 50000
NGRP <- 50
NCOL <- 100

test.case <- data.frame(i=1:SIZE)
test.case[["grouping"]] <- sample(NGRP, size=SIZE, replace=TRUE, prob=1/(1:NGRP))
test.case[["y"]] <- sample(c(0, 1), size=SIZE, replace=TRUE, prob=c(0.05, 0.95))

test.formula = y ~ (1 | grouping)

for (i in 1:NCOL) {
    colname <- paste("col", i, sep="")
    test.case[[colname]] <- runif(SIZE)
    test.formula <- update.formula(test.formula, as.formula(paste(". ~ . +", colname)))
}

print(test.formula)

test.model <- glmer(test.formula, data=test.case, family='binomial', verbose=TRUE)

Questo produce:

start par. =  1 fn =  19900.78 
At return
eval:  15 fn:      19769.402 par:  0.00000
(NM) 20: f = 19769.4 at           0     <other numbers>
(NM) 40: f = 19769.4 at           0     <other numbers>

Ho provato a impostare ncolaltri valori e sembra che il numero di iterazioni effettuate sia (circa) 40 per colonna. Ovviamente, questo diventa un grande dolore quando aggiungo più colonne. Ci sono modifiche che posso apportare all'algoritmo di ottimizzazione che ridurrà la dipendenza dal numero di colonne?


1
Sarebbe utile conoscere il modello specifico che stai cercando di adattare (in particolare la struttura degli effetti casuali).
Patrick S. Forscher,

Purtroppo il modello preciso è proprietario. Esiste un livello di effetti casuali, con gruppi di dimensioni comprese tra ~ 100 e 5000. Fammi sapere se posso fornire altre informazioni rilevanti sul modello.
Ben Kuhn,

OK, ho aggiunto del codice che riproduce il problema.
Ben Kuhn,

1
Non ho una risposta completa per te, quindi la lascerò come commento. Nella mia esperienza, glmerè piuttosto lento, specialmente per i modelli che hanno una struttura complessa di effetti casuali (ad es. Molte pendenze casuali, effetti casuali incrociati, ecc.). Il mio primo suggerimento sarebbe di riprovare con una struttura di effetti casuali semplificata. Tuttavia, se stai riscontrando questo problema solo con un modello di intercettazione casuale, il tuo problema potrebbe essere semplicemente il numero di casi, nel qual caso dovrai provare alcuni strumenti specializzati per i big data.
Patrick S. Forscher,

Ha lo stesso problema con 2 gruppi anziché 50. Inoltre, testando con un numero minore di colonne, sembra che il numero di iterazioni sia approssimativamente lineare nel numero di colonne ... Esistono metodi di ottimizzazione che faranno meglio qui ?
Ben Kuhn,

Risposte:


12

Una cosa che potresti provare è cambiare l'ottimizzatore. Vedi il commento di Ben Bolker a questo numero di github . L'implementazione nlopt di bobyqa è in genere molto più veloce di quella predefinita (almeno ogni volta che la provo).

library(nloptr)
defaultControl <- list(algorithm="NLOPT_LN_BOBYQA",xtol_rel=1e-6,maxeval=1e5)
nloptwrap2 <- function(fn,par,lower,upper,control=list(),...) {
    for (n in names(defaultControl)) 
      if (is.null(control[[n]])) control[[n]] <- defaultControl[[n]]
    res <- nloptr(x0=par,eval_f=fn,lb=lower,ub=upper,opts=control,...)
    with(res,list(par=solution,
                  fval=objective,
                  feval=iterations,
                  conv=if (status>0) 0 else status,
                  message=message))
}

system.time(test.model <- glmer(test.formula, data=test.case, 
family='binomial', verbose=TRUE))

system.time(test.model2 <- update(test.model,
control=glmerControl(optimizer="nloptwrap2"))

Inoltre, vedi questa risposta per ulteriori opzioni e questa discussione da R-sig-mixed-models (che sembra più rilevante per il tuo problema).

Modifica: ti ho dato alcune informazioni obsolete relative a nloptr. In lme4 1.1-7e su, nloptrviene importato automaticamente (vedi ?nloptwrap). Tutto quello che devi fare è aggiungere

control = [g]lmerControl(optimizer = "nloptwrap") # +g if fitting with glmer

alla tua chiamata.


Grazie! Sto provando il codice nlopt in questo momento. Mi chiedo se ci sia qualcosa di diverso da una cattiva implementazione dell'ottimizzatore in corso, dal momento che montare un glm simmetrico quasi equivalente era molto più veloce, ma vedrò ...
Ben Kuhn,

Beh, è stato sicuramente più veloce, ma si è fermato con un errore: PIRLS step-halvings failed to reduce deviance in pwrssUpdate. Hai idea di cosa potrebbe succedere qui? Il messaggio di errore non è esattamente trasparente ...
Ben Kuhn

Per i calci, potresti provare a impostare nAGQ = 0 (vedi il thread che ho collegato per qualche altra idea). Non ricordo che cosa causa l'errore PIRLS, ma mi guarderò intorno.
alexforrence,

Grazie mille! Potresti indicarmi una risorsa in cui potrei saperne di più sui dettagli di questi metodi in modo da poter risolvere problemi come questo in futuro? Al momento l'ottimizzazione è molto simile alla magia nera.
Ben Kuhn,

2
nAGQ = 0 ha funzionato per me nel tuo esempio di test con il bobyqa predefinito (eseguito in ~ 15 secondi) e in 11 secondi con il nloptrbobyqa. Ecco un'intervista a John C. Nash (coautore del pacchetto optime optimx) dove fa una spiegazione di alto livello sull'ottimizzazione. Se cerchi optimxo nloptrsu CRAN, i rispettivi manuali di riferimento ti diranno di più sulla sintassi. nloptrha anche una vignetta disponibile, che va un po 'più in dettaglio.
alexforrence,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.