Generalized Linear Mixed Models (GLMM)

INTRODUCTION

Generalized Linear Mixed Models (GLMM) method combines the characteristics of the Generalized Linear Model (GLM), with mixed models (such a repeated measures over time). It extends the GLM framework using link functions that relate the predictors to transformed outcome variable.

\[ E(Y)=\mu \]

\[ g(\mu) = X\beta + Zb, \qquad b \sim N(0, G) \]

Where:

n: number of observations, p: number of fixed effects, q: number of random effects (subjects).

Y: vector of observed response variable (n x 1)

g: Link function that transforms Y to the linear scale (eg: logit)

X: matrix for fixed effects (n x p), Z: matrix of random effects, G: covariance matrix of the random effects.

B: vector of fixed effects coefficients (p x 1)., b: vector of random effects.

Link Function:

  • Dichotomous response variable: probit (in case of rare events complementary log-log may be preferable).

  • Outcomes with more than two categories:

    • Ordinal variable: cumulative

    • Nominal variable: generalized logit

Random Effects

GLMM are conditional models and estimate subject-average effects, and the intra-subject correlation is modelled via random effects. Unlike GEE models, GLMM models allow individual-level inference.

Estimation Methods

Maximum likelihood, based on approximations:

  • Gauss Hermite Quadrature (GHQ): Integral split in a given number of points.

  • Laplace: A specific case of GHQ, using 1 point.

Penalized Likelihood can be used too, but it is known that in binary data it underestimates variance components and biased results.

EXAMPLE DATA

A SAS data of clinical trial data comparing two treatments for a respiratory disorder available in “Gee Model for Binary Data” [1] in the SAS/STAT Sample Program Library [1] is used to create these examples.

To uniquely identify subjects, a new variable USUBJID was created by concatenating SITE and ID. Variables TREATMENT, BASELINE, and VISIT were renamed to TRTP, BASE, and AVISITN.

Additionally, two variables were created using randomly generated values to simulate variables with more than two categories. One was an ordinal variable with values 1, 2, and 3; the other was a nominal variable with categories ‘liver’, ‘lung’, and ‘bone’. Data were created in SAS (See SAS section), and imported in R.

The variables OUTCOME, TRTP, RESPORD, USUBJID and AVISITN were converted to factors. Since the modeling functions use the first (alphabetically) level as the reference category, TRT levels are ordered as ‘P’ (placebo) and ‘A’ (active), to ensure that placebo is used as the reference category in the models:

library(readxl)
resp <- read_excel("../data/resp_gee.xlsx")
resp$trtp<-factor(resp$trtp, levels=c('P', 'A')) 
resp$avisitn<-factor(resp$avisitn) 
resp$outcome<-factor(resp$outcome)
resp$usubjid<-factor(resp$usubjid)
resp$respord<-factor(resp$respord)

PACKAGES

library(lme4)
Loading required package: Matrix
library(GLMMadaptive)

Attaching package: 'GLMMadaptive'
The following object is masked from 'package:lme4':

    negative.binomial
library(merDeriv)
Loading required package: nonnest2
This is nonnest2 0.5-8.
nonnest2 has not been tested with all combinations of supported model classes.
Loading required package: sandwich
Loading required package: lavaan
This is lavaan 0.6-21
lavaan is FREE software! Please report any bugs.
library(parameters)
library(glmmTMB)

Attaching package: 'glmmTMB'
The following objects are masked from 'package:sandwich':

    meatHC, sandwich
library(clubSandwich)
Registered S3 methods overwritten by 'clubSandwich':
  method        from    
  bread.lmerMod merDeriv
  bread.mlm     sandwich
library(MASS)

Attaching package: 'MASS'
The following object is masked from 'package:GLMMadaptive':

    negative.binomial
library(emmeans)
Welcome to emmeans.
Caution: You lose important information if you filter this package's results.
See '? untidy'
library(ordinal)

GLMM WITH GHQ

GLMM with GHQ approximation can be fitted using lme4::glmer andGLMMadaptative::mixed_modelR functions.

In GLMMs, intra‑subject (within‑cluster) correlation is captured through the inclusion of random effects. Both functions estimate this correlation by assuming normally distributed random effects with infinite degrees of freedom and, by default, model the random‑effects covariance matrix GGG using a Variance Components (VC) structure.

lme::glmer

The syntax to fit a GLMM using GHQ with lme4::glme is displayed below, the random effects are specified as 1|usubjid , where the number 1 denotes a random intercept (different baseline for each individual). By specifying nAQG=<n> the GHQ method is applied with the specified number of points (in this example n=5).

model <- lme4::glmer(outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid), 
               data = resp,
               family = binomial(link ="logit"),
               nAGQ=5)

summary(model)
Generalized linear mixed model fit by maximum likelihood (Adaptive
  Gauss-Hermite Quadrature, nAGQ = 5) [glmerMod]
 Family: binomial  ( logit )
Formula: outcome ~ trtp + avisitn + trtp * avisitn + (1 | usubjid)
   Data: resp

      AIC       BIC    logLik -2*log(L)  df.resid 
    487.2     524.0    -234.6     469.2       435 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.1952 -0.3744  0.2062  0.4089  2.1081 

Random effects:
 Groups  Name        Variance Std.Dev.
 usubjid (Intercept) 6.963    2.639   
Number of obs: 444, groups:  usubjid, 111

Fixed effects:
               Estimate Std. Error z value Pr(>|z|)  
(Intercept)    -0.06177    0.52741  -0.117   0.9068  
trtpA           1.57505    0.78352   2.010   0.0444 *
avisitn2       -0.87192    0.54763  -1.592   0.1113  
avisitn3       -0.28729    0.53694  -0.535   0.5926  
avisitn4       -0.43176    0.53860  -0.802   0.4228  
trtpA:avisitn2  1.04386    0.80358   1.299   0.1939  
trtpA:avisitn3  0.63613    0.79997   0.795   0.4265  
trtpA:avisitn4 -0.22003    0.78660  -0.280   0.7797  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) trtpA  avstn2 avstn3 avstn4 trtA:2 trtA:3
trtpA       -0.676                                          
avisitn2    -0.497  0.317                                   
avisitn3    -0.505  0.334  0.496                            
avisitn4    -0.503  0.330  0.499  0.500                     
trtpA:vstn2  0.338 -0.482 -0.683 -0.339 -0.341              
trtpA:vstn3  0.338 -0.488 -0.336 -0.672 -0.337  0.495       
trtpA:vstn4  0.346 -0.518 -0.334 -0.340 -0.681  0.495  0.496

GLMMadapive::mixed_model

The syntax using GLMMadaptative::mixed_model is similar, but the random effects are specified by using the random argument.

model <- GLMMadaptive::mixed_model(fixed = outcome ~ trtp + avisitn  + trtp*avisitn,
             random = ~1|usubjid,
             data = resp,
             family = binomial(link = "logit"),
             nAGQ=5)
summary(model)

Call:
GLMMadaptive::mixed_model(fixed = outcome ~ trtp + avisitn + 
    trtp * avisitn, random = ~1 | usubjid, data = resp, family = binomial(link = "logit"), 
    nAGQ = 5)

Data Descriptives:
Number of Observations: 444
Number of Groups: 111 

Model:
 family: binomial
 link: logit 

Fit statistics:
   log.Lik      AIC      BIC
 -234.5954 487.1909 511.5767

Random effects covariance matrix:
              StdDev
(Intercept) 2.680307

Fixed effects:
               Estimate Std.Err z-value p-value
(Intercept)     -0.0760  0.5806 -0.1308 0.89590
trtpA            1.6388  0.8728  1.8776 0.06044
avisitn2        -0.8746  0.5475 -1.5974 0.11017
avisitn3        -0.2890  0.5374 -0.5377 0.59080
avisitn4        -0.4335  0.5390 -0.8043 0.42123
trtpA:avisitn2   1.0461  0.8031  1.3026 0.19272
trtpA:avisitn3   0.6375  0.8000  0.7969 0.42553
trtpA:avisitn4  -0.2188  0.7875 -0.2778 0.78118

Integration:
method: adaptive Gauss-Hermite quadrature rule
quadrature points: 5

Optimization:
method: hybrid EM and quasi-Newton
converged: TRUE 

Results produced by the mixed_model function show slight deviations when compared to glmer, suggesting differences in the model implementation or estimation.

Even with Gauss–Hermite quadrature in both, lme4::glmer and GLMMadaptive::mixed_model use different likelihood parameterizations, adaptive quadrature implementations, and optimization routines, so they don’t evaluate the exact same objective and can yield different estimates (especially for non-Gaussian outcomes or sparse data). In practice, mixed_model() tends to provide more accurate marginal likelihood integration (subject-specific adaptive scaling), while glmer() is faster but more approximate, which can bias variance components and slightly shift fixed effects [2].

GLMM WITH LAPLACE

Laplace is a particular GHQ where only one point is used. In R, lme4::glmer can also be used to compute Laplace approximation, but not GLMMadaptative::mixed_model. The glmmTMB::glmmTMBfunction is also a viable alternative.

lme::glmer

The syntax using lme4::glmer is the same as in GHQ, but without specifying the number of points:

model <- lme4::glmer(formula =outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid),
               data = resp,
                family = binomial(link ="logit"))
Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl = control$checkConv, : Model failed to converge with max|grad| = 0.00926468 (tol = 0.002, component 1)
  See ?lme4::convergence and ?lme4::troubleshooting.
summary(model)
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: binomial  ( logit )
Formula: outcome ~ trtp + avisitn + trtp * avisitn + (1 | usubjid)
   Data: resp

      AIC       BIC    logLik -2*log(L)  df.resid 
    493.4     530.2    -237.7     475.4       435 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.1946 -0.3899  0.2097  0.4216  2.0956 

Random effects:
 Groups  Name        Variance Std.Dev.
 usubjid (Intercept) 6.433    2.536   
Number of obs: 444, groups:  usubjid, 111

Fixed effects:
               Estimate Std. Error z value Pr(>|z|)  
(Intercept)    -0.08269    0.52044  -0.159   0.8738  
trtpA           1.64646    0.78036   2.110   0.0349 *
avisitn2       -0.85805    0.54287  -1.581   0.1140  
avisitn3       -0.28067    0.53169  -0.528   0.5976  
avisitn4       -0.42263    0.53331  -0.792   0.4281  
trtpA:avisitn2  1.02843    0.79405   1.295   0.1953  
trtpA:avisitn3  0.62119    0.79067   0.786   0.4321  
trtpA:avisitn4 -0.20289    0.77543  -0.262   0.7936  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) trtpA  avstn2 avstn3 avstn4 trtA:2 trtA:3
trtpA       -0.675                                          
avisitn2    -0.497  0.310                                   
avisitn3    -0.508  0.331  0.495                            
avisitn4    -0.506  0.327  0.497  0.500                     
trtpA:vstn2  0.339 -0.474 -0.685 -0.339 -0.340              
trtpA:vstn3  0.340 -0.482 -0.336 -0.674 -0.338  0.493       
trtpA:vstn4  0.350 -0.510 -0.336 -0.342 -0.685  0.496  0.496
optimizer (Nelder_Mead) convergence code: 0 (OK)
Model failed to converge with max|grad| = 0.00926468 (tol = 0.002, component 1)
  See ?lme4::convergence and ?lme4::troubleshooting.

This initial attempt using lme4::glmerresulted in a convergence warning, which can be addressed by switching the optimizer to “bobyqa” and extending the maximum number of iterations, as shown in the code below. These adjustments not only suppress the warning but provides closer results to SAS [3].

model <- lme4::glmer(formula =outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid),
               data = resp,
                family = binomial(link ="logit"),
                nAGQ=1,
                control=lme4::glmerControl(optimizer="bobyqa",                    
                        optCtrl=list(maxfun=100000)))
summary(model)
Generalized linear mixed model fit by maximum likelihood (Laplace
  Approximation) [glmerMod]
 Family: binomial  ( logit )
Formula: outcome ~ trtp + avisitn + trtp * avisitn + (1 | usubjid)
   Data: resp
Control: 
lme4::glmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 1e+05))

      AIC       BIC    logLik -2*log(L)  df.resid 
    493.4     530.2    -237.7     475.4       435 

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-2.1964 -0.3901  0.2097  0.4213  2.0951 

Random effects:
 Groups  Name        Variance Std.Dev.
 usubjid (Intercept) 6.44     2.538   
Number of obs: 444, groups:  usubjid, 111

Fixed effects:
               Estimate Std. Error z value Pr(>|z|)  
(Intercept)    -0.08475    0.52067  -0.163   0.8707  
trtpA           1.65139    0.78093   2.115   0.0345 *
avisitn2       -0.85752    0.54293  -1.579   0.1142  
avisitn3       -0.28186    0.53178  -0.530   0.5961  
avisitn4       -0.42356    0.53339  -0.794   0.4271  
trtpA:avisitn2  1.02468    0.79414   1.290   0.1969  
trtpA:avisitn3  0.62207    0.79088   0.787   0.4315  
trtpA:avisitn4 -0.20495    0.77559  -0.264   0.7916  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Correlation of Fixed Effects:
            (Intr) trtpA  avstn2 avstn3 avstn4 trtA:2 trtA:3
trtpA       -0.675                                          
avisitn2    -0.497  0.310                                   
avisitn3    -0.508  0.331  0.495                            
avisitn4    -0.506  0.326  0.497  0.500                     
trtpA:vstn2  0.339 -0.473 -0.685 -0.339 -0.340              
trtpA:vstn3  0.340 -0.482 -0.336 -0.673 -0.338  0.493       
trtpA:vstn4  0.350 -0.510 -0.336 -0.342 -0.685  0.496  0.496
model <- glmer(formula =outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid),
               data = resp,
                family = binomial(link ="logit"),
                nAGQ=1,
                control=glmerControl(optimizer="bobyqa",                    
                        optCtrl=list(maxfun=100000)))

glmmTMB::glmmTMB

The glmmTMB::glmmTMB function is also a viable alternative for Laplace approximation, with similar syntax to lme4::glmer.

model<- glmmTMB::glmmTMB(outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid),
                data = resp,
                family = binomial(link = "logit"))
summary(model)
 Family: binomial  ( logit )
Formula:          outcome ~ trtp + avisitn + trtp * avisitn + (1 | usubjid)
Data: resp

      AIC       BIC    logLik -2*log(L)  df.resid 
    493.4     530.2    -237.7     475.4       435 

Random effects:

Conditional model:
 Groups  Name        Variance Std.Dev.
 usubjid (Intercept) 6.442    2.538   
Number of obs: 444, groups:  usubjid, 111

Conditional model:
               Estimate Std. Error z value Pr(>|z|)  
(Intercept)    -0.08476    0.52073  -0.163   0.8707  
trtpA           1.65178    0.78148   2.114   0.0345 *
avisitn2       -0.85758    0.54300  -1.579   0.1143  
avisitn3       -0.28190    0.53181  -0.530   0.5961  
avisitn4       -0.42359    0.53344  -0.794   0.4271  
trtpA:avisitn2  1.02474    0.79432   1.290   0.1970  
trtpA:avisitn3  0.62216    0.79103   0.786   0.4316  
trtpA:avisitn4 -0.20503    0.77578  -0.264   0.7916  
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Although both glmmTMB and lme4::glmer implement the Laplace approximation for fitting GLMMs, they rely on different numerical frameworks and optimization strategies. glmmTMB uses TMB with automatic differentiation and its own Laplace implementation, whereas glmer uses lme4’s custom penalized deviance formulation and derivative‑free optimizers. As a result, the approximated likelihoods, gradients, and optimization paths differ, leading to non‑identical parameter estimates even under the same model specification. [2]

PENALIZED QUASI-LIKELIHOOD (PQL)

The PQL approach uses linear approximations instead of likelihood, making it less accurate for binary outcomes compared to the GHQ or Laplace methods described above. PQL computation can be obtained using the glmmPQL function form the MASS package, using the random argument to specify the random factors.

model <- MASS::glmmPQL(outcome ~ trtp + avisitn + trtp*avisitn,
                 random=list(~1|usubjid),
                 data = resp,
                 family = binomial(link = "logit"))
iteration 1
iteration 2
iteration 3
iteration 4
iteration 5
iteration 6
summary(model)
Linear mixed-effects model fit by maximum likelihood
  Data: resp 
  AIC BIC logLik
   NA  NA     NA

Random effects:
 Formula: ~1 | usubjid
        (Intercept)  Residual
StdDev:    2.240666 0.7414888

Variance function:
 Structure: fixed weights
 Formula: ~invwt 
Fixed effects:  outcome ~ trtp + avisitn + trtp * avisitn 
                    Value Std.Error  DF    t-value p-value
(Intercept)     0.0000080 0.4125606 327  0.0000194  1.0000
trtpA           1.2202691 0.6029058 109  2.0239797  0.0454
avisitn2       -0.8149934 0.3942084 327 -2.0674177  0.0395
avisitn3       -0.2682000 0.3879416 327 -0.6913412  0.4898
avisitn4       -0.4033782 0.3890430 327 -1.0368474  0.3006
trtpA:avisitn2  0.9759879 0.5795035 327  1.6841796  0.0931
trtpA:avisitn3  0.5950261 0.5780995 327  1.0292797  0.3041
trtpA:avisitn4 -0.1998455 0.5678652 327 -0.3519241  0.7251
 Correlation: 
               (Intr) trtpA  avstn2 avstn3 avstn4 trtA:2 trtA:3
trtpA          -0.684                                          
avisitn2       -0.464  0.317                                   
avisitn3       -0.467  0.319  0.495                            
avisitn4       -0.466  0.319  0.496  0.498                     
trtpA:avisitn2  0.315 -0.469 -0.680 -0.337 -0.338              
trtpA:avisitn3  0.313 -0.467 -0.332 -0.671 -0.334  0.492       
trtpA:avisitn4  0.319 -0.485 -0.340 -0.341 -0.685  0.500  0.497

Standardized Within-Group Residuals:
       Min         Q1        Med         Q3        Max 
-2.8440535 -0.4341097  0.2723992  0.4824627  2.8108150 

Number of Observations: 444
Number of Groups: 111 

Note: glmmPQL is widely recognized as less reliable for binary outcomes, more robust approaches such as Laplace or GHQ discussed in previous sections are generally preferred.

SANDWICH SE AND DEGREES OF FREEDOM (DDFF)

Previous results are computed using default outputs, so naive SE and infinite ddff are used. However, Li. P. and Redden, D.T. (2015) [4], suggested using the Between-Within denominator degrees of freedom approximation method when using GLMMs in randomized trials with binary outcomes and small sample size.

Additionally, FDA [5] advises “sponsors to consider using of robust SE method such as the Huber-White”sandwich” SE, particularly when the model does not include treatment by covariate interaction.

In R, the functions described above do not include these options. Function parameters::dof_betwithin can be used to use between-withing ddff, does it would not return exactly the same results as shown in Li and Redden 2015 [4], but similar results are obtained [6].

The Sandwich S.E. can be obtained from different functions too: merDeriv::sandwich function can be used for glmer objects, and clubSandwich::vovHC for glmmTMB objects (recent versions of the package R (>= 3.6.0) support the computation of Sandwich S.E. using the using clubSandwich::vcovHC function [7].

A function ‘new_mode’ is created below, where results obtained from a glmer model can be modified to use the sandwich SE and the between-within approximated ddff:

lme::glmer

new_model <- function(model, est_fix , se , df){
#Re-calculate (2-sided) p-values using estimated parameters and its SE
t <- est_fix /se
pvalue <-2*pt(q=abs(t), df=df, lower.tail=FALSE)
#Combine results in a data frame and add row names
new_model <- round(cbind(est_fix, se, df, t, pvalue), digits=4)
colnames(new_model) <- c("Estimate", "Std. Error", "df", "tvalue", "P-value")
rownames(new_model) <- rownames(summary(model)$coefficients)
new_model
}
#Run the model
model <- lme4::glmer(outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid), 
               data = resp,
               family = binomial(link ="logit"),
               nAGQ=5)


#Get parameter estimation
est<-lme4::fixef(model)

#Get Sandwich covariance matrix
library(merDeriv)
vcov<-sandwich(model)

#Get S.E. (the diagonal from the covariance matrix), remove last value as it corresponds to random effects
se_sw0<- sqrt(diag(vcov)) 
se_sw <-head(se_sw0, -1)
#Re-calculate p-values using Sandwich SE and Inf ddff
new_model(model, est_fix=est, se=se_sw , df=Inf )
               Estimate Std. Error  df  tvalue P-value
(Intercept)     -0.0618     0.5378 Inf -0.1149  0.9086
trtpA            1.5751     0.7914 Inf  1.9902  0.0466
avisitn2        -0.8719     0.5391 Inf -1.6172  0.1058
avisitn3        -0.2873     0.6102 Inf -0.4708  0.6378
avisitn4        -0.4318     0.5164 Inf -0.8361  0.4031
trtpA:avisitn2   1.0439     0.8220 Inf  1.2699  0.2041
trtpA:avisitn3   0.6361     0.8589 Inf  0.7407  0.4589
trtpA:avisitn4  -0.2200     0.7939 Inf -0.2772  0.7817
#Re-calculate p-values using Sandwich SE and between-within ddff
new_model(model, est_fix=est, se=se_sw , df=parameters::dof_betwithin(model))
               Estimate Std. Error  df  tvalue P-value
(Intercept)     -0.0618     0.5378 324 -0.1149  0.9086
trtpA            1.5751     0.7914 324  1.9902  0.0474
avisitn2        -0.8719     0.5391 324 -1.6172  0.1068
avisitn3        -0.2873     0.6102 324 -0.4708  0.6381
avisitn4        -0.4318     0.5164 324 -0.8361  0.4037
trtpA:avisitn2   1.0439     0.8220 324  1.2699  0.2050
trtpA:avisitn3   0.6361     0.8589 324  0.7407  0.4594
trtpA:avisitn4  -0.2200     0.7939 324 -0.2772  0.7818

glmmTMB::glmmTMB

new_model <- function(model, est_fix , se , df){
#Re-calculate (2-sided) p-values using estimated parameters and its SE
t <- est_fix /se
pvalue <-2*pt(q=abs(t), df=df, lower.tail=FALSE)
#Combine results in a data frame and add row names
new_model <- round(cbind(est_fix, se, df, t, pvalue), digits=4)
colnames(new_model) <- c("Estimate", "Std. Error", "df", "tvalue", "P-value")
rownames(new_model) <- rownames(summary(model)$coefficients$cond)
new_model
}
#Run the model
model<- glmmTMB::glmmTMB(outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid),
data = resp,
family = binomial(link = "logit"))

#Get estimator
est<-glmmTMB::fixef(model)$cond

#Get Sandwich S.E.
se_sw<- sqrt(diag(vcovHC(model)))
#Re-calculate p-values with Sandwich SE and Ininite df
new_model(model, est_fix=est, se=se_sw , df=Inf )
               Estimate Std. Error  df  tvalue P-value
(Intercept)     -0.0848     0.5452 Inf -0.1555  0.8765
trtpA            1.6518     0.8182 Inf  2.0188  0.0435
avisitn2        -0.8576     0.5302 Inf -1.6175  0.1058
avisitn3        -0.2819     0.5986 Inf -0.4709  0.6377
avisitn4        -0.4236     0.5069 Inf -0.8357  0.4033
trtpA:avisitn2   1.0247     0.8026 Inf  1.2767  0.2017
trtpA:avisitn3   0.6222     0.8397 Inf  0.7410  0.4587
trtpA:avisitn4  -0.2050     0.7727 Inf -0.2653  0.7907
#Re-calculate p-values with Sandwich SE between-withing aprox. df
new_model(model, est_fix=est, se=se_sw , df=parameters::dof_betwithin(model))
               Estimate Std. Error  df  tvalue P-value
(Intercept)     -0.0848     0.5452 324 -0.1555  0.8766
trtpA            1.6518     0.8182 324  2.0188  0.0443
avisitn2        -0.8576     0.5302 324 -1.6175  0.1067
avisitn3        -0.2819     0.5986 324 -0.4709  0.6380
avisitn4        -0.4236     0.5069 324 -0.8357  0.4039
trtpA:avisitn2   1.0247     0.8026 324  1.2767  0.2026
trtpA:avisitn3   0.6222     0.8397 324  0.7410  0.4592
trtpA:avisitn4  -0.2050     0.7727 324 -0.2653  0.7909

PREDICTED PROBABILITIES AND ODDS RATIO (OR)

Estimated probabilities and ORs, obtained by using the emmeans and contrast functions. In the example below, the probabilities and OR are estimated for GLMM using GHQ approximation.

To obtain robust (sandwich) standard errors, the emmeans function allows specifying a sandwich covariance estimator using vcov.method = sandwich(model), as illustrated in the example below. To instead use the model‑based (naive) standard errors, simply supply the model’s own covariance matrix by specifying vcov.method = vcov(model).

#Run the model
model <- lme4::glmer(outcome ~ trtp + avisitn + trtp*avisitn + (1 | usubjid), 
               data = resp,
               family = binomial(link ="logit"),
               nAGQ=5)
library(emmeans)
#Get predicted probabilities for each treatment, using the Sandwich matrix covariance
prob <- emmeans(model, ~ trtp*avisitn, data=resp, vcov.method=sandwich(model), type='response')
prob
 trtp avisitn  prob     SE  df asymp.LCL asymp.UCL
 P    1       0.485 0.1320 Inf     0.251     0.726
 A    1       0.820 0.0854 Inf     0.594     0.934
 P    2       0.282 0.1090 Inf     0.120     0.531
 A    2       0.844 0.0772 Inf     0.631     0.944
 P    3       0.414 0.1280 Inf     0.200     0.666
 A    3       0.866 0.0691 Inf     0.668     0.954
 P    4       0.379 0.1250 Inf     0.177     0.634
 A    4       0.703 0.1150 Inf     0.445     0.875

Confidence level used: 0.95 
Intervals are back-transformed from the logit scale 
#Get differences between treatments by visit (option "revpairwise" is used to compare A vs P)
diffs_mean<-emmeans(model, ~ trtp*avisitn, data=resp, vcov.method=sandwich(model))
diffs <- contrast(diffs_mean,"revpairwise", simple="trtp")
diffs <- as.data.frame(diffs)

#Calculate CI (alpha=0.05)
alpha<-0.05
z_crit <- qnorm(1 - alpha / 2)
diffs$low<-diffs$estimate - (z_crit*diffs$SE)
diffs$upp<-diffs$estimate + (z_crit*diffs$SE)

#Get OR applying exponential transformation;
or<-exp(diffs$estimate)
or_low<-exp(diffs$low)
or_upp<-exp(diffs$up)

#Get two-sided p-value
z <- diffs$estimate/diffs$SE
pvalue <- 2 * (1 - pnorm(z))

#Create a dataset with all the results
OR<-as.data.frame(cbind(diffs$avisitn, or,or_low, or_upp, z, round(pvalue, digits=4)))
colnames(OR)<-c('avisit', 'OR', 'lower.CL', 'upper.CL', 'Z', 'p-value')
OR
  avisit        OR  lower.CL upper.CL        Z p-value
1      1  4.830986 1.0401682 22.43716 2.010228  0.0444
2      2 13.720725 2.8152984 66.86975 3.240837  0.0012
3      3  9.126521 1.8973419 43.90004 2.759125  0.0058
4      4  3.876834 0.8558308 17.56170 1.757983  0.0788

OUTCOME WITH MORE THAN TWO CATEGORIES

Although less common than binary outcomes, endpoints with more than two categories may be the outcome of interest, which can be either ordinal or nominal. In those case, the multinomial distribution is used selecting the appropriated link function depending on the type of response variable.

Ordinal variable

The function ordinal::clmm can be used to fit a GLMM model when the outcome is an ordinal variable.

model<- ordinal::clmm(respord ~ trtp + avisitn + trtp*avisitn + (1 | usubjid), 
             data = resp)
summary(model)
Cumulative Link Mixed Model fitted with the Laplace approximation

formula: respord ~ trtp + avisitn + trtp * avisitn + (1 | usubjid)
data:    resp

 link  threshold nobs logLik  AIC    niter     max.grad cond.H 
 logit flexible  444  -482.20 984.40 666(1357) 6.84e-04 1.7e+02

Random effects:
 Groups  Name        Variance Std.Dev.
 usubjid (Intercept) 0.1511   0.3887  
Number of groups:  usubjid 111 

Coefficients:
               Estimate Std. Error z value Pr(>|z|)
trtpA          -0.43273    0.36062  -1.200    0.230
avisitn2        0.01155    0.35236   0.033    0.974
avisitn3       -0.10700    0.35079  -0.305    0.760
avisitn4        0.17114    0.34838   0.491    0.623
trtpA:avisitn2  0.26152    0.50072   0.522    0.601
trtpA:avisitn3  0.57356    0.50391   1.138    0.255
trtpA:avisitn4  0.31098    0.49794   0.625    0.532

Threshold coefficients:
    Estimate Std. Error z value
1|2  -0.5630     0.2573  -2.188
2|3   0.6573     0.2589   2.539

Nominal variable

No R functions have been identified for handling multinomial distributions for a nominal variable in a frequentist framework.

REFERENCES

[1] SAS Institute Inc.. SAS Help Center. The GEE procedure.

[2] Conceptual explanations were assisted using Microsoft Copilot (M365 Copilot, GPT‑5‑based model).

[3] Stack Overflow [Internet]. 2008 [Last visited: 2025 Sep 30]

[4] Li, P., & Redden, D. T. (2015). Comparing denominator degrees of freedom approximations for the generalized linear mixed model in analyzing binary outcome in small sample cluster-randomized trials. BMC Medical Research Methodology, 15, 38.

[5] U.S. Food and Drug Administration. (2023). Adjusting for Covariates in Randomized Clinical Trials for Drugs and Biological Products: Guidance for Industry. Center for Drug Evaluation and Research (CDER), Center for Biologics Evaluation and Research (CBER).

[6] Documentation of package parameters. dof_betwithin

[7] Brooks, M. E., et al. (2025). glmmTMB: Generalized Linear Mixed Models using Template Model Builder (Version 1.1.12) [R package manual]. The Comprehensive R Archive Network (CRAN). https://cran.r-project.org/web/packages/glmmTMB/glmmTMB.pdf

[8] Ordinal: Regression Models for Ordinal Data.