Understanding categorical predictors in a mixed-effects model
Categorical predictors
Mixed-effects models
R
Author
Nora Wickelmaier
Published
November 5, 2024
This post is meant to give you a better understanding how to interpret parameters for categorical predictors in a mixed-effects model. Understanding what the parameters mean is helpful when simulating data, e.g., for power simulations.
Example
This is an example where three different media are compared to each other: A Multi-Touch Table (MTT) and two different Virtual Reality conditions (VR1 and VR2). These are all presented to every subject (within-factor mediatype). Additionally, we have a between-factor interaction with levels passive and active. Subjects can either actively interact for all media types or they can just passively look at things presented to them with the three different media types. The dependent varible is immersion. Subjects should feel more immersed when actively interacting and Virtual Reality should also lead to more immersion than a Multi-Touch Table.
library(lme4)# Data simulation for a 2 (between) x 3 (within) designset.seed(1046)n <-100dat <-data.frame(id =factor(rep(1:n, each =3)),mediatype =factor(c("MTT", "VR1", "VR2")),interaction =factor(rep(c("active", "passive"), each =3),levels =c("passive", "active")))## Set parametersbeta <-c(.5, .2, .3, .4, .7, .4)sigma <- .8spi <- .5theta <- spi / sigma## Simulate datadat$y <-simulate(~1+ mediatype + interaction + mediatype:interaction + (1| id),newparam =list(beta = beta, theta = theta, sigma = sigma),newdata = dat)$sim_1## Visualize simulated datadatm <-aggregate(y ~ mediatype + interaction, data = dat, FUN = mean)colors <-c("#3CB4DC", "#91C86E")par(mai =c(.8, .8, .1, .1), mgp =c(2.4, 1, 0))plot(y ~I(1:3), data = datm[datm$interaction =="passive", ],xlab ="Media type",ylab ="Immersion",xlim =c(0.5, 3.5),ylim =c(-2, 4),axes =FALSE,type ="n")axis(1, at =1:3, labels =c("MTT", "VR1", "VR2"))axis(2)box()points(y ~jitter(as.numeric(mediatype)), data = dat,col = colors[dat$interaction])points(y ~I(1:3), datm[datm$interaction =="passive", ], col = colors[1],type ="b", pch =16, cex =2)points(y ~I(1:3), datm[datm$interaction =="active", ], col = colors[2],type ="b", pch =16, cex =2)text(1.45, 0.4, "passive", col = colors[1])text(1.4, 1.6, "active", col = colors[2])
with \(\upsilon_0 \sim N(0, \sigma^2_{\upsilon_0})\) and \(\varepsilon \sim N(0, \sigma^2_{\varepsilon})\)
## Fit linear mixed-effects modelm1 <-lmer(y ~1+ mediatype + interaction + mediatype:interaction + (1| id),data = dat)tab <-summary(m1)$coefci <-confint(m1)
Estimate
Std. Error
t value
2.5 %
97.5 %
(Intercept)
0.421
0.128
3.295
0.172
0.670
mediatypeVR1
0.439
0.146
3.014
0.155
0.723
mediatypeVR2
0.393
0.146
2.702
0.110
0.677
interactionactive
0.499
0.181
2.763
0.147
0.852
mediatypeVR1:interactionactive
0.474
0.206
2.304
0.073
0.876
mediatypeVR2:interactionactive
0.280
0.206
1.357
-0.122
0.681
Implied model formulae
The two categorical predictors are dummy coded. For interaction the level passive is set as reference category. The dummy variable \(interaction_{active}\) is therefore 0 for passive and 1 for active.
contrasts(dat$interaction)
active
passive 0
active 1
The three level factor mediatype is represented by two dummy variables, namely \(mediatype_{VR1}\) and \(mediatype_{VR2}\). Since MTT is the reference category, the coding scheme is as folows.
contrasts(dat$mediatype)
VR1 VR2
MTT 0 0
VR1 1 0
VR2 0 1
When we plug these dummy variables into the model formula from above, we get the following equations for each data point of the aggregated data set.
\[\begin{align*}
y_{11} & = \beta_0 + \upsilon_0 + \varepsilon & \text{value for an average person for the reference categories (MTT and passive)}\\
y_{12} & = \beta_0 + \beta_1 + \upsilon_0 + \varepsilon & \text{effect when going from MTT to VR1 for passive}\\
y_{13} & = \beta_0 + \beta_2 + \upsilon_0 + \varepsilon & \text{effect when going from MTT to VR2 for passive}\\
y_{21} & = \beta_0 + \beta_3 + \upsilon_0 + \varepsilon & \text{effect when going from passive to active for MTT}\\
y_{22} & = \beta_0 + \beta_1 + \beta_3 + \beta_4 + \upsilon_0 + \varepsilon & \text{effect when going from MTT to VR1 for active}\\
y_{23} & = \beta_0 + \beta_2 + \beta_3 + \beta_5 + \upsilon_0 + \varepsilon & \text{effect when going from MTT to VR2 for active}\\
\end{align*}\]
Compare to plot
Session info
sessionInfo()
R version 4.6.1 (2026-06-24 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 26100)
Matrix products: default
LAPACK version 3.12.1
locale:
[1] LC_COLLATE=German_Germany.utf8 LC_CTYPE=German_Germany.utf8
[3] LC_MONETARY=German_Germany.utf8 LC_NUMERIC=C
[5] LC_TIME=German_Germany.utf8
time zone: Europe/Berlin
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] lme4_2.1-0 Matrix_1.7-6
loaded via a namespace (and not attached):
[1] digest_0.6.39 fastmap_1.2.0 xfun_0.62 lattice_0.23-1
[5] splines_4.6.1 knitr_1.52 htmltools_0.5.9 rmarkdown_2.32
[9] Rdpack_2.6.6 cli_3.6.6 nloptr_2.2.1 grid_4.6.1
[13] reformulas_0.4.4 compiler_4.6.1 rbibutils_2.4.1 boot_1.3-32
[17] tools_4.6.1 nlme_3.1-171 minqa_1.2.8 evaluate_1.0.5
[21] Rcpp_1.1.2 yaml_2.3.12 otel_0.2.0 rlang_1.3.0
[25] jsonlite_2.0.0 htmlwidgets_1.6.4 MASS_7.3-66