Подходит для многих моделей glm: улучшите скорость

Я пишу функцию, подходящую для многих моделей glm. Чтобы просто дать вам некоторое представление об этой функции, я включаю небольшой фрагмент своего кода. С помощью нескольких пользователей SO функция теперь работает для моей цели анализа. Однако иногда, особенно когда размер выборки относительно невелик, завершение всего процесса может занять довольно много времени. Чтобы сократить время, я рассматриваю возможность изменения некоторых деталей итеративной максимизации, таких как максимальное количество итераций. Я не нашел способа сделать это, может быть, потому, что я еще не знаком с R терминологией. Любые предложения сделать это или другие способы сократить время будут оценены.

all_glm <- function(crude, xlist, data, family = "binomial", ...) {
  # md_lst include formula for many models to be fitted  
  comb_lst <- unlist(lapply(1:n, function(x) combn(xlist, x, simplify=F)), recursive=F)
  md_lst   <- lapply(comb_lst,function(x) paste(crude, "+", paste(x, collapse = "+")))
  models  <- lapply(md_lst, function(x) glm(as.formula(x), family = family, data = data))
  OR      <- unlist(lapply(models, function(x) broom::tidy(x, exponentiate = TRUE)$estimate[2]))

}    

EDIT Благодаря @BenBolker, который направил меня к пакету fastglm, я получил несколько пакетов r, которые могли бы предоставить более быстрые альтернативы glm. Я пробовал fastglm и speedglm. Оказывается, оба быстрее, чем glm на моей машине.

library(fastglm)
library(speedglm)
# from 
set.seed(1)
n <- 25000
k <- 500
y <- rbinom(n, size = 1, prob = 0.5)
x <- round( matrix(rnorm(n*k),n,k),digits=3)
colnames(x) <-paste("s",1:k,sep = "")
df <- data.frame(y,x)
fo <- as.formula(paste("y~",paste(paste("s",1:k,sep=""),collapse="+")))   

# Fit three models: 
system.time(m_glm <- glm(fo, data=df, family = binomial))
system.time(m_speedglm <- speedglm(fo, data= df, family = binomial()))
system.time(m_fastglm <- fastglm(x, y, family = binomial()))

> system.time(m_glm <- glm(fo, data=df, family = binomial))
   user  system elapsed 
  56.51    0.22   58.73 
> system.time(m_speedglm <- speedglm(fo, data= df, family = binomial()))
   user  system elapsed 
  17.28    0.04   17.55 
> system.time(m_fastglm <- fastglm(x, y, family = binomial()))
   user  system elapsed 
  23.87    0.09   24.12 

r glm
person Zhiqiang Wang    schedule 17.10.2019    source источник
comment
пробовали ли вы пакет fastglm?   -  person Ben Bolker    schedule 18.10.2019
comment
@BenBolker Спасибо. Нет, я не пробовал, я попробую посмотреть, будет ли это иметь значение.   -  person Zhiqiang Wang    schedule 18.10.2019
comment
@BenBolker Я пробовал fastglm. Он позволяет пользователям назначать пороговый допуск для сходимости и максимальное количество итераций, но требует, чтобы x был матричным объектом, что может быть неудобно для некоторых конечных пользователей.   -  person Zhiqiang Wang    schedule 18.10.2019
comment
все ваши предикторы числовые или некоторые факторы (категориальные)? минимально воспроизводимый пример был бы замечательным. Каковы типичные размеры вашей проблемы (количество наблюдений, количество предикторов)? Рассматривали ли вы штрафной подход (лассо/гребень)?   -  person Ben Bolker    schedule 18.10.2019
comment
В сочетании с переменными numeric и factor. Я хотел бы сделать функцию универсальной для разных типов предикторов. Я постараюсь разработать воспроизводимый пример. Спасибо.   -  person Zhiqiang Wang    schedule 18.10.2019
comment
Это самая маленькая из заметок. Я не знаю более быстрой реализации в R, однако с небольшой хитростью, возможно, openGL или другие полностью основанные на c++ реализации могут быть немного быстрее. Что касается проблемы с fastglm, разрешающей только числовые x и y, я предлагаю использовать стандартный вызов glm glm(fo, data = df, family = binomial, method = "fastglm"). Вызов glm позаботится о преобразовании вашей формулы в матрицу модели и даст необходимые данные для fastglm. Обратите внимание, что печать вывода занимает много времени, если вы используете этот метод (по неизвестным мне причинам).   -  person Oliver    schedule 18.10.2019
comment
@Oliver Приятно знать, как работает method = ! Я не могу использовать fastglm в своей функции по другой причине: не могу broom::tidy() использовать объект fastglm. speedglm работает нормально. Большое спасибо!   -  person Zhiqiang Wang    schedule 19.10.2019


Ответы (1)


Алгоритм IRLS, обычно используемый для подбора glms, требует инверсии/декомпозиции матрицы на каждой итерации. fastglm предлагает несколько различных вариантов декомпозиции, и по умолчанию выбран более медленный, но более стабильный вариант (QR с поворотом столбцов). Если вас интересует только скорость, то одна из двух доступных декомпозиций типа Холецкого значительно улучшит скорость, что было бы более целесообразно, чем простое изменение количества итераций IRLS. Еще одно заметное различие между fastglm и стандартной реализацией IRLS заключается в осторожном использовании полушагов для предотвращения расхождений (на практике IRLS может расходиться в ряде случаев).

Аргумент method функции fastglm позволяет изменить разложение. вариант 2 дает ванильное разложение Холецкого, а вариант 3 дает немного более стабильную версию этого. На моем компьютере тайминги для предоставленного вами примера:

> system.time(m_glm <- glm(fo, data=df, family = binomial))
   user  system elapsed 
 23.206   0.429  23.689 

> system.time(m_speedglm <- speedglm(fo, data= df, family = binomial()))
   user  system elapsed 
 15.448   0.283  15.756 

> system.time(m_fastglm <- fastglm(x, y, family = binomial(), method = 2))
   user  system elapsed 
  2.159   0.055   2.218 

> system.time(m_fastglm <- fastglm(x, y, family = binomial(), method = 3))
   user  system elapsed 
  2.247   0.065   2.337 

Что касается использования метлы с объектами fastglm, я могу изучить это.

Еще одно замечание о декомпозиции: когда fastglm использует декомпозицию QR, она напрямую работает с матрицей проекта. Хотя speedglm технически предлагает QR-разложение, оно работает, сначала вычисляя $X^TX$ и разлагая его, что более численно неустойчиво, чем QR на X.

person jjdd    schedule 02.11.2019
comment
Большое спасибо. Я узнал кое-что интересное и полезное из вашего ответа. - person Zhiqiang Wang; 03.11.2019