Fitting the same glmer model to multiple subsets of the same data

45 Views Asked by At

I am trying to address basically the same question as in this post, but I can't seem to apply this to glmer instead of lmer.

I have a rather complex model that looks something like this:

 mod1 <- glmer(outcome ~
                 var1*var0 +
                 var2*var0 +
                 var3+
                 var4+
                 (1+var0|subj),
               family=binomial("logit"),

          control=glmerControl(calc.derivs=FALSE,
                                    optimizer="bobyqa",
                                    optCtrl=list(maxfun=2e5)),
               data=subset(mydata, var5 == T))

Which I want to split by another variable, var6, of which there are 7 levels, and run this model for each subset.

To illustrate using the sleepstudy data, and using the edits to create two new variables - Group as in the post I link above, as well as sex:

 data(sleepstudy)
 sleepstudy$group <- car::recode(sleepstudy$Subject,
   "c('308','309','310','330','331','332','333','334') = 'group1'; 
     c('335','337','349','350','351','352','369','370','371','372') = 'group2'")
 sleepstudy$sex <- car::recode(sleepstudy$Subject,
                   "c('308','310','331','333','335','349','351','369','371') = 'm';
   c('309','330','332','334','337','350','352','370','372') = 'f'")
 
 model<-glmer(group~Days+Reaction+(1|Subject), 
                family=binomial("logit"),
                          data=sleepstudy)

In this example I would want to run this model twice, split by sex. Is there a way I can do this quickly and efficiently to extract the coefficients from each model?

1

There are 1 best solutions below

2
Ben Bolker On

With tidyverse, this would be:

library(tidyverse)
library(broom.mixed)
library(lme4)
 sleepstudy$group <- car::recode(sleepstudy$Subject,
   "c('308','309','310','330','331','332','333','334') = 'group1'; 
     c('335','337','349','350','351','352','369','370','371','372') = 'group2'")
 sleepstudy$sex <- car::recode(sleepstudy$Subject,
                   "c('308','310','331','333','335','349','351','369','371') = 'm';
   c('309','330','332','334','337','350','352','370','372') = 'f'")
(sleepstudy
   |> split(sleepstudy$sex)
   |> purrr::map(~glmer(group~Days+Reaction+(1|Subject), 
                family=binomial("logit"),
                data = .))
   |> purrr::map_dfr(~tidy(., effects = "fixed"), .id = "sex")
)

(hardcore tidyverse users would use nest() + mutate() + unnest() to make list-columns, similar to this example.)

In base R, after using split(), you can

(sleepstudy
   |> split(sleepstudy$sex)
   |> lapply( \(.) glmer(group~Days+Reaction+(1|Subject), 
                family=binomial("logit"),
                data = .))
   |> lapply(fixef)
)

(you could also lapply(summary) for the last step). Running do.call("rbind", ...) on the results will produce a data frame (but you won't have the convenience of having the sex variable included in the result).