This lesson is still being designed and assembled (Pre-Alpha version)

Mixed Effects Models

Overview

Teaching: 60 min
Exercises: 30 min
Questions
  • How do you analyse data if observations are not independent of each other?

Objectives
  • Model data with correlated observations.

Prerequisites

  • Experience with R, including importing, processing, and plotting of data.
  • Basic familiarity with multiple linear regression.

R packages used: dplyr, ggplot2, lattice, lme4, lmerTest, readr

Discuss

One assumption of multiple linear regression is that observations are independent of each other. What are examples where this assumption may be violated?

Modelling clustered data

Definition

A unit of observation is an object about which information is collected independently of other units.

Examples include an individual, a family, a neighbourhood.

Units of observation may be related to each other, forming groups or clusters.

Individuals could be grouped in families, or schools. Families could be clustered by neighbourhood. Schools could be clustered by state.

Longitudinal data also consist of clusters of observations made at different occasions for the same subject.

Clustered data violate the assumption of independent observations. It is usually helpful, and often critical, to reflect the structure present in the data in the model. Careful modelling of these clusters will help you to separate variations in the response due to experimental conditions (or other effect of interest) from those that are due to the intrinsic structure of the data.

Modelling the height of siblings

Let’s look how this works with some real data. In this section we will analyse the height data collected by Francis Galton in 1885. It consists of the heights (measured in inches) of the adult children from 197 families. We start by importing the data.

library(readr)
height <- read_table2("../data/Galton.tab", col_types = cols(Family = col_character()))
height
# A tibble: 898 x 6
   Family Father Mother Gender Height  Kids
   <chr>   <dbl>  <dbl> <chr>   <dbl> <dbl>
 1 1        78.5   67   M        73.2     4
 2 1        78.5   67   F        69.2     4
 3 1        78.5   67   F        69       4
 4 1        78.5   67   F        69       4
 5 2        75.5   66.5 M        73.5     4
 6 2        75.5   66.5 M        72.5     4
 7 2        75.5   66.5 F        65.5     4
 8 2        75.5   66.5 F        65.5     4
 9 3        75     64   M        71       2
10 3        75     64   F        68       2
# ... with 888 more rows

As you can see there are 898 individual observations with information on family membership and gender. Before delving into the analysis we should take a closer look at the data.

length(unique(height$Family))
[1] 197
table(height$Gender)

  F   M 
433 465 
summary(height$Kids)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  1.000   4.000   6.000   6.136   8.000  15.000 

We would expect that height is influenced by gender. We can confirm this based on numerical and graphical summaries of the data. We’ll use dplyr for processing the data and ggplot2 for plotting.

library(dplyr)
height %>% group_by(Gender) %>% summarise(mean=mean(Height)) %>% ungroup()
# A tibble: 2 x 2
  Gender  mean
  <chr>  <dbl>
1 F       64.1
2 M       69.2
library(ggplot2)

ggplot(height, aes(x=Gender, y=Height, fill=Gender)) + geom_violin() + theme_bw()

plot of chunk unnamed-chunk-1

Based on this, a reasonable first model might be to simply estimate the average height of males and females in the population. Using lm we can express this as

fit_lm <- lm(Height ~ Gender, data=height)

We can look at some model diagnostics to confirm that this is an appropriate model.

qqnorm(rstandard(fit_lm))
qqline(rstandard(fit_lm), col=2)

plot of chunk height_lm_qc

Exercise

When fitting a linear regression model you should always inspect the residuals and their relationship with the fitted values. Usually a scatter plot is helpful for this purpose. Since this model only produces two different predictions (one for males and one for females), that isn’t very helpful here.

  • What type of plot could you use to examine the residuals instead?
  • What would you expect that plot to look like?
  • Create and examine the plot.

Solution

A boxplot or violin plot can help to summarise the distribution of residuals by group. Since the model simply estimates the mean heights of males and females a violin plot of the residuals should look very similar to the violin plot of heights above, but with the means of both groups aligned at 0.

ggplot(height, aes(x=Gender, y=resid(fit_lm), fill=Gender)) +
   geom_violin() +
   theme_bw()

plot of chunk unnamed-chunk-2

Now let’s take a look at the model output:

summary(fit_lm)

Call:
lm(formula = Height ~ Gender, data = height)

Residuals:
    Min      1Q  Median      3Q     Max 
-9.2288 -1.6102 -0.1102  1.7712  9.7712 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  64.1102     0.1206  531.70   <2e-16 ***
GenderM       5.1187     0.1676   30.55   <2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 2.509 on 896 degrees of freedom
Multiple R-squared:  0.5102,	Adjusted R-squared:  0.5096 
F-statistic: 933.2 on 1 and 896 DF,  p-value: < 2.2e-16

According to this the average height of women is 64.11 inches and men are, on average, 5.12 inches taller than women.

This all looks fairly reasonable but clearly there is a lot of variation in height not explained by gender. We would expect siblings to be somewhat similar in height as they share genetic factors through their parents and environmental factors through their shared upbringing.

We can model this structure of the data, children clustering in families, using linear mixed effects models. In addition to estimating population means (fixed effects) these models will also allow us to estimate how average family heights vary around these population means (random effects).

We will use the lmer() function from the lme4 R package to fit mixed effects models.

library(lme4)
Loading required package: Matrix
fit_me <- lmer(Height ~ Gender + (1|Family), data=height)

As you can see, lmer() uses a formula syntax similar to lm(). In addition to the already familiar fixed effect for gender this model includes an additional term, (1|Family). This specifies the random effect for family, indicating that the mean height of each family may differ from the population mean.

Now, let’s take a closer look at the model.

summary(fit_me)
Linear mixed model fit by REML ['lmerMod']
Formula: Height ~ Gender + (1 | Family)
   Data: height

REML criterion at convergence: 4007.8

Scaled residuals: 
    Min      1Q  Median      3Q     Max 
-3.9475 -0.5661  0.0067  0.5937  3.5069 

Random effects:
 Groups   Name        Variance Std.Dev.
 Family   (Intercept) 2.448    1.564   
 Residual             3.843    1.960   
Number of obs: 898, groups:  Family, 197

Fixed effects:
            Estimate Std. Error t value
(Intercept)  64.1489     0.1542  415.92
GenderM       5.1529     0.1418   36.33

Correlation of Fixed Effects:
        (Intr)
GenderM -0.486

In addition to the gender fixed effect that we have already seen in the simple linear regression model, this model also provides us with an estimate of the variance in average height between families (2.45) as well as the remaining (residual) variance within families (3.84).

A dot plot, also known as a caterpillar plot, can help to visualise random effects. The lme4 package, in conjunction with the lattice package, provides a convenient function to create these plots.

library(lattice)

randoms <- ranef(fit_me)
dotplot(randoms)
$Family

plot of chunk height_dotplot

This plot shows the deviation from the mean population height for each family, together with standard errors. Note how some families fall clearly below or above the population mean.

You can create Q-Q plots for random effects in a similar way, using the qqmath() function.

qqmath(randoms)
$Family

plot of chunk height_qqplot

Model comparison with anova() and ranova()

You can compare the mixed effects model to the multiple regression model using anova() in the same way you would compare two different multiple regression models. For this to work, you have to fit the model using maximum likelihood, rather than the default restricted maximum likelihood, and the first argument to anova() has to be the lmer model.

## Re-fit model using ML, rather than REML
fit_me <- lmer(Height ~ Gender + (1|Family), data=height, REML=FALSE)
anova(fit_me, fit_lm)
Data: height
Models:
fit_lm: Height ~ Gender
fit_me: Height ~ Gender + (1 | Family)
       Df    AIC    BIC  logLik deviance  Chisq Chi Df Pr(>Chisq)    
fit_lm  3 4204.5 4218.9 -2099.3   4198.5                             
fit_me  4 4011.6 4030.8 -2001.8   4003.6 194.94      1  < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

In this case, the inclusion of the family random effect clearly improves model fit, with all the provided metrics favouring the mixed effects model. It is sometimes desirable to compare models with different random effect structures to decide which random effects should be included. Although lme4 doesn’t provide an easy way to do that, you can augment its abilities with the lmerTest package. To do so, you’ll have to load the lmerTest package after lme4 but prior to fitting the model.

library(lme4)
library(lmerTest)

fit_me <- lmer(Height ~ Gender + (1|Family), data=height)

Then you can use the ranova() function to compare models with different random effects structure.

ranova(fit_me)
ANOVA-like table for random-effects: Single term deletions

Model:
Height ~ Gender + (1 | Family)
             npar  logLik    AIC    LRT Df Pr(>Chisq)    
<none>          4 -2003.9 4015.8                         
(1 | Family)    3 -2101.7 4209.4 195.56  1  < 2.2e-16 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

The comparison between the model with a random intercept for family (the mixed effects model) and the model without any random effects (the simple regression model) again shows that the mixed effects model is clearly preferred.

Investigating the relationship between pitch and politeness

In this section you will apply what you just learned to explore a dataset from a study (Winter and Grawunder, 2012) designed to investigate the relationship between voice pitch and politeness.

Subjects are asked to respond to hypothetical scenarios that are from either formal situations that require politeness or more informal situations and voice pitch is measured. Each subject is given a list of all the scenarios, so each subject gives multiple polite or informal responses. Gender is also recorded, since it is known to influence voice pitch.

Let’s take a look at the structure of the data:

politeness_data <- read_csv(file.path("..", "data", "politeness_data.csv"))

politeness_data
# A tibble: 80 x 6
   subject gender scenario attitude total_duration frequency
   <chr>   <chr>     <dbl> <chr>             <dbl>     <dbl>
 1 F1      F             1 pol               18.4       215.
 2 F1      F             1 inf               13.6       211.
 3 F1      F             2 pol                5.22      285.
 4 F1      F             2 inf                4.25      266.
 5 F1      F             3 pol                6.79      211.
 6 F1      F             3 inf                4.13      286.
 7 F1      F             4 pol                6.24      252.
 8 F1      F             4 inf                3.24      282.
 9 F1      F             5 pol                5.62      230.
10 F1      F             5 inf                3.95      250.
# ... with 70 more rows
table(politeness_data$subject)

F1 F3 F7 F8 M1 M3 M5 M7 
10 10 10 10 10 10 10 10 
table(politeness_data$subject, politeness_data$attitude)
    
     inf pol
  F1   5   5
  F3   5   5
  F7   5   5
  F8   5   5
  M1   5   5
  M3   5   5
  M5   5   5
  M7   5   5

There are observations from 8 subjects. Each subject has provided speech samples for 5 different scenarios using both a polite and informal voice.

Exercise

Download the exercise starter code. Follow the instructions in the R script file to carry out an analysis of the pitch and politeness data.

Solution

You can take a look at a sample solution online.

References

Winter, B. (2013). Linear models and linear mixed effects models in R with linguistic applications. arXiv:1308.5499.

https://web.stanford.edu/class/psych252/section/Mixed_models_tutorial.html#model-comparison

https://www.youtube.com/watch?v=VhMWPkTbXoY

https://stat.ethz.ch/R-manual/R-devel/library/MASS/html/oats.html

https://www.statmethods.net/management/typeconversion.html

https://cran.r-project.org/web/packages/lme4/lme4.pdf

https://cran.r-project.org/web/packages/lme4/vignettes/lmer.pdf

https://www.r-bloggers.com/linear-mixed-models-in-r/

https://bbolker.github.io/morelia_2018/notes/mixedlab.html

Key Points

  • Use lmer() to fit mixed effects models that account for clustered observations.

  • Use diagnostic plots (dotplot() and qqmath()) to assess the model fit for mixed models.

  • Use the ranova() function to assess which random effects should be included in the model.