Оптимізатор lme4 за замовчуванням потребує безлічі ітерацій для об'ємних даних


12

TL; DR: lme4оптимізація виявляється лінійним по числу параметрів моделі за замовчуванням, і шлях повільніше , ніж аналогічна glmмодель з фіктивними змінними для груп. Чи можна щось зробити, щоб прискорити це?


Я намагаюся вписати досить велику ієрархічну модель logit (~ 50k рядків, 100 стовпців, 50 груп). Встановлення нормальної моделі logit до даних (з фіктивними змінними для групи) працює нормально, але ієрархічна модель, схоже, зациклюється: перша фаза оптимізації завершується прекрасно, але друга проходить через безліч ітерацій, не змінюючи нічого і не зупиняючись. .

EDIT: Я підозрюю, що проблема полягає в основному в тому, що в мене так багато параметрів, тому що коли я намагаюся встановити maxfnнижче значення, воно дає попередження:

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

Однак оцінки параметрів взагалі не змінюються протягом оптимізації, тому я все ще плутаюсь, що робити. Коли я намагався встановити maxfnв оптимізаторі елементи керування (незважаючи на попередження), здавалося, висіло після завершення оптимізації.

Ось код, який відтворює проблему для випадкових даних:

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)

Цей результат:

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>

Я спробував встановити ncolінші значення, і, здається, кількість виконаних ітерацій становить (приблизно) 40 на стовпчик. Очевидно, це стає величезним болем, оскільки я додаю більше колонок. Чи можна змінити алгоритм оптимізації, який зменшить залежність від кількості стовпців?


1
Було б корисно знати конкретну модель, до якої ви намагаєтесь підходити (особливо структуру випадкових ефектів).
Патрік С. Форшер

На жаль, точна модель є власною. Існує один рівень випадкових ефектів, розміри груп - від 100 до 5000. Повідомте мене, чи можу я надати будь-яку іншу релевантну інформацію про модель.
Бен Кун

Гаразд, я додав код, який відтворює проблему.
Бен Кун

1
У мене немає повної відповіді для вас, тому я залишаю це як коментар. На мій досвід, glmerдосить повільно, особливо для моделей, які мають складну структуру випадкових ефектів (наприклад, багато випадкових нахилів, перехрещених випадкових ефектів тощо). Першою моєю пропозицією було б спробувати ще раз спрощену структуру випадкових ефектів. Однак якщо ви зіткнулися з цією проблемою лише з випадковою моделлю перехоплення, вашою проблемою може бути просто кількість випадків, і в цьому випадку вам потрібно буде спробувати деякі інструменти, спеціалізовані для великих даних.
Патрік С. Форшер

У нього однакова проблема з 2 групами замість 50. Крім того, тестуючи меншу кількість стовпців, здається, що кількість ітерацій приблизно лінійна за кількістю стовпців ... Чи існують методи оптимізації, які будуть робити тут краще ?
Бен Кун

Відповіді:


12

Можна спробувати одне - змінити оптимізатор. Дивіться коментар Бена Болкера до цього питання про github . Реалізація bobyqa в nlopt, як правило, набагато швидша, ніж за замовчуванням (принаймні, коли я це намагаюся).

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"))

Також дивіться цю відповідь для отримання додаткових варіантів і цей потік від R-sig-змішаних моделей (що виглядає більш актуально для вашої проблеми).

Редагувати: Я дав вам деяку застарілу інформацію, пов’язану зnloptr . Увімкнений lme4 1.1-7і вище, nloptrавтоматично імпортується (див. ?nloptwrap) Все, що вам потрібно зробити - це додати

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

на ваш дзвінок.


Дякую! Я зараз пробую код nlopt. Мені цікаво, чи відбувається щось інше, ніж погана реалізація оптимізатора, оскільки встановлення майже еквівалентного деміфікованого glm було набагато швидше, але я побачу ...
Бен Кун

Ну, це, звичайно , швидше, але вона зупинилася з помилкою: PIRLS step-halvings failed to reduce deviance in pwrssUpdate. Чи маєте ви якесь уявлення, що тут може статися? Повідомлення про помилку не зовсім прозоре ...
Бен Кун

Для ударів ви можете спробувати встановити nAGQ = 0 (див. Нитку, яку я пов’язав ще для кількох ідей). Я не пам'ятаю, що викликає помилку ПІРЛІ, але я огляну навколо.
alexforrence

Дуже дякую! Не могли б ви вказати мені на ресурс, де я міг би дізнатися більше про деталі цих методів, щоб я міг самостійно вирішити подібні проблеми в майбутньому? На сьогодні оптимізація дуже схожа на чорну магію.
Бен Кун

2
nAGQ = 0 працював для мене на вашому тестовому прикладі за замовчуванням bobyqa (пробіг за ~ 15 сек) та за 11 сек з nloptrbobyqa. Ось інтерв'ю з Джоном К. Нешем (співавтором пакетів optimта optimxпакунків), де він роз'яснює оптимізацію на високому рівні. Якщо ви подивитесь на CRAN optimxабо nloptrна нього, їх відповідні посібники розкажуть більше про синтаксис. nloptrтакож є в наявності віньєтка, яка йде трохи далі в деталі.
alexforrence
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.