Оптимізатор 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.