Оптимизатор lme4 по умолчанию требует много итераций для многомерных данных


12

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


Я пытаюсь соответствовать довольно большой иерархической модели логита (~ 50 тыс. Строк, 100 столбцов, 50 групп). Подгонка нормальной модели логита к данным (с фиктивными переменными для группы) работает нормально, но иерархическая модель, похоже, застревает: первая фаза оптимизации завершается нормально, но вторая проходит много итераций без каких-либо изменений и без остановки ,

РЕДАКТИРОВАТЬ: я подозреваю, что проблема в основном в том, что у меня так много параметров, потому что, когда я пытаюсь установить 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-mixed-models (которая выглядит более актуальной для вашей проблемы).

Редактировать: Я дал вам устаревшую информацию, связанную с nloptr. В lme4 1.1-7и вверх, nloptrавтоматически импортируется (см. ?nloptwrap). Все, что вам нужно сделать, это добавить

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

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


Спасибо! Я пытаюсь код nlopt прямо сейчас. Я действительно задаюсь вопросом, есть ли что-то кроме плохой реализации оптимизатора, так как установка почти эквивалентного dmmified glm была намного быстрее, но я посмотрю ...
Бен Кун

Ну, это, конечно , быстрее, но она остановилась с ошибкой: PIRLS step-halvings failed to reduce deviance in pwrssUpdate. Ты хоть представляешь, что здесь происходит? Сообщение об ошибке не совсем прозрачно ...
Бен Кун

Для получения удовольствия вы можете попробовать установить nAGQ = 0 (см. Нить, на которую я ссылаюсь, для получения дополнительной информации). Я не помню, что вызывает ошибку PIRLS, но я посмотрю вокруг.
alexforrence

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

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