Chapter 15 Linear Model and Mixed Methods
Note: this section is partically adapted from Fox (2002), Linear Mixed Models and Bates et al (2015) . We will frist focus on simple linear model, we extend it to fixed effect model, finally we discuss random effects modelling. We will alose use the data from study of Belenky et al (2003). This is pretty famous dataset that is easy to find online and you may find some help on it easily as many people are using it either to teach or to learn about random effects.
15.1 Longitudinal Data
We have seen quite a few examples of linear models earlier this week, let us now finally get to the ones you probably came here to learn more about. The world can be slighlty more complex of course than traditional set up of linear models. Things change in time and they change differently for differnt units of analysis. We want to control for the variation in this change when making claims about casual relationship we find using data. In psychological research, especially, you often find that you will have some repeated measures of your variable of interest for participants (i.e. memory after perfoming certain tests, reaction scores, attitudes, etc). These are realted either to multiple treatments given to participatns of measuring the same relationships at different time points.
Remember old model set up: \[\begin{equation} Y_[i] = \beta_0 + \beta_1 * X_i + \epsilon_i \end{equation}\]
And remember the assumptions that are required for the linear model Once in repeated measures setting you will see that most of these will remain. As in the simple linear model,we do care most about our residual term. We want it to be random and normally distributed with zero mean. The main reason for that of course is the fact that we want our model to explain all the meaningful variations without leaving anything in the residual term.
The only difference we have now is the we want to control for each individual unobserved characteristics so we introduce extra parameter which will account for those.
\[\begin{equation} Y_[i] = \beta_0 + \beta_1 * X_i + \alpha + \epsilon_i \end{equation}\]
This is the fixed effect model.
We can also introduce further parameters that will allows us to include effects at individual levels (i.e. pupils) and at the entity levels (i.e.schools)
\[\begin{equation} Y_[i] = \beta_0 + \beta_1 * X_i + \theta_i + \gamma_ij + \epsilon_i \end{equation}\]
15.2 Why do we do this?
The reason why we are introducing a new model for repeated measures data or data that has few levels is the consideration of Ecological fallacy. What do we mean by that is that there may be differences across the effects on the levels of units compared to that on individual levels. Lets look at the example of the data:
Do you think we have positive relationship or negative? is it easy to tell what is happening?
15.3 Ecological Fallacy (quick illustration)
Lets get some data in and load lmer package:
library(lme4)
disease<-read.csv('disease.csv')
We will run three models:
#Not controlling for city
model_0 <- lm(HDisease~Income, data = disease)
#Controlling for city effects
model_1 <- lm(HDisease~Income+factor(City), data = disease)
#Controlling for city and across cities effects
model_2 <- lmer(HDisease~Income + (1 | City), data = disease)
Lets compare the outputs:
library(texreg)
screenreg(list(model_0, model_1, model_2))
##
## =========================================================
## Model 1 Model 2 Model 3
## ---------------------------------------------------------
## (Intercept) 1.65 *** 3.07 *** 16.41 ***
## (0.27) (0.11) (2.87)
## Income 1.95 *** -0.99 *** -0.98 ***
## (0.05) (0.07) (0.07)
## factor(City)2 2.88 ***
## (0.16)
## factor(City)3 5.96 ***
## (0.21)
## factor(City)4 8.91 ***
## (0.26)
## factor(City)5 12.06 ***
## (0.33)
## factor(City)6 14.89 ***
## (0.40)
## factor(City)7 17.78 ***
## (0.47)
## factor(City)8 20.90 ***
## (0.54)
## factor(City)9 23.86 ***
## (0.59)
## factor(City)10 26.93 ***
## (0.68)
## ---------------------------------------------------------
## R^2 0.95 1.00
## Adj. R^2 0.95 1.00
## Num. obs. 100 100 100
## RMSE 1.34 0.32
## AIC 148.61
## BIC 159.03
## Log Likelihood -70.31
## Num. groups: City 10
## Var: City (Intercept) 81.14
## Var: Residual 0.10
## =========================================================
## *** p < 0.001, ** p < 0.01, * p < 0.05
15.4 Simple model
Lets load all the packages we will need:
library(lattice)
library(arm)
We will use the data on sleep deprivation. The example is based on Belenky et al (2003) study that looks at patterns of sleeping across individuals that are doing through the stages of sleep deprivation. On day 0 the subjects had their normal amount of sleep. Starting that night they were restricted to 3 hours of sleep per night. The observations represent the average reaction time on a series of tests given each day to each subject.
sleep<-read.csv('sleep.csv')
Lets just plot the data as it is. We will use Days as our X, and reaction as our Y. You will recognize something we just have seen.
qplot(sleep$Days, sleep$Reaction, xlab='Days', ylab='Reaction')
It is a hard to tell whether there is a positive effect or whether there may be different levels of effect, it is clearly that there is some tendency for increasing reaction as time passes but we have various individuals we may find that on individual levels we may observe a more detailed picture.
We can use xy plot to plot the variation of reaction time for the test which were given to participants across ten days of the recovery.
xyplot(Reaction ~ Days|Subject, sleep, type = c("g","p","r"),
index = function(x,y) coef(lm(y ~ x))[1],
xlab = "Days of sleep deprivation",
ylab = "Average reaction time (ms)", aspect = "xy")
What do you see? It looks like for some individuals there were pretty fast changes in the reactions times across periods with some having steady growth in reaction level.
Note how in the plots I included the variables Days|Subject, sleep. This helps to identify that we are looking at the effect of time for each subject’s sleep variable.
Let us now see if we were to run a model to fit this data.
15.4.1 Pooling
We can start with simple model, this is also know as complete polling, we assume that effects of variable Day were the same for everyone.
model_simple<-lm(Reaction~Days, sleep)
summary(model_simple)
##
## Call:
## lm(formula = Reaction ~ Days, data = sleep)
##
## Residuals:
## Min 1Q Median 3Q Max
## -110.848 -27.483 1.546 26.142 139.953
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 251.405 6.610 38.033 < 2e-16 ***
## Days 10.467 1.238 8.454 9.89e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 47.71 on 178 degrees of freedom
## Multiple R-squared: 0.2865, Adjusted R-squared: 0.2825
## F-statistic: 71.46 on 1 and 178 DF, p-value: 9.894e-15
15.4.2 No pooling
We can also control for each subject, this is known as fixed effect and is equivalent to having a dummy variable for each of the individuals:
model_subject<-lm(Reaction~Days+as.factor(Subject), sleep)
summary(model_subject)
##
## Call:
## lm(formula = Reaction ~ Days + as.factor(Subject), data = sleep)
##
## Residuals:
## Min 1Q Median 3Q Max
## -100.540 -16.389 -0.341 15.215 131.159
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 295.0310 10.4471 28.240 < 2e-16 ***
## Days 10.4673 0.8042 13.015 < 2e-16 ***
## as.factor(Subject)309 -126.9008 13.8597 -9.156 2.35e-16 ***
## as.factor(Subject)310 -111.1326 13.8597 -8.018 2.07e-13 ***
## as.factor(Subject)330 -38.9124 13.8597 -2.808 0.005609 **
## as.factor(Subject)331 -32.6978 13.8597 -2.359 0.019514 *
## as.factor(Subject)332 -34.8318 13.8597 -2.513 0.012949 *
## as.factor(Subject)333 -25.9755 13.8597 -1.874 0.062718 .
## as.factor(Subject)334 -46.8318 13.8597 -3.379 0.000913 ***
## as.factor(Subject)335 -92.0638 13.8597 -6.643 4.51e-10 ***
## as.factor(Subject)337 33.5872 13.8597 2.423 0.016486 *
## as.factor(Subject)349 -66.2994 13.8597 -4.784 3.87e-06 ***
## as.factor(Subject)350 -28.5311 13.8597 -2.059 0.041147 *
## as.factor(Subject)351 -52.0361 13.8597 -3.754 0.000242 ***
## as.factor(Subject)352 -4.7123 13.8597 -0.340 0.734300
## as.factor(Subject)369 -36.0992 13.8597 -2.605 0.010059 *
## as.factor(Subject)370 -50.4321 13.8597 -3.639 0.000369 ***
## as.factor(Subject)371 -47.1498 13.8597 -3.402 0.000844 ***
## as.factor(Subject)372 -24.2477 13.8597 -1.750 0.082108 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 30.99 on 161 degrees of freedom
## Multiple R-squared: 0.7277, Adjusted R-squared: 0.6973
## F-statistic: 23.91 on 18 and 161 DF, p-value: < 2.2e-16
We can test whether controlling for each individual variation improves on a simple model:
anova(model_simple, model_subject)
## Analysis of Variance Table
##
## Model 1: Reaction ~ Days
## Model 2: Reaction ~ Days + as.factor(Subject)
## Res.Df RSS Df Sum of Sq F Pr(>F)
## 1 178 405252
## 2 161 154634 17 250618 15.349 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
However you should note that in this structure we do not consider anything with regards to between units variation, we are looking at what happening within individuals reaction but do not compare them
15.4.3 Partial Pooling (varying intercepts)
An attempt do so can be using random effect modelling structure. This will first look at the variation between individuals and then measure their distance from average individual effect, so we are partially pooling everyone together. Please note that we are assuming the slopes are the same, it is the intercepts that will vary for each person.
#Run baseline model (will use it later for comparison, we have no controls)
model_null <- lmer(Reaction ~ (1|Subject) , sleep)
#Run the model (note thay we also control for the effect of time by subject)
model_mix <- lmer(Reaction ~ Days + (1|Subject) , sleep)
#Summarise
summary(model_mix)
## Linear mixed model fit by REML ['lmerMod']
## Formula: Reaction ~ Days + (1 | Subject)
## Data: sleep
##
## REML criterion at convergence: 1786.5
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -3.2257 -0.5529 0.0109 0.5188 4.2506
##
## Random effects:
## Groups Name Variance Std.Dev.
## Subject (Intercept) 1378.2 37.12
## Residual 960.5 30.99
## Number of obs: 180, groups: Subject, 18
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 251.4051 9.7467 25.79
## Days 10.4673 0.8042 13.02
##
## Correlation of Fixed Effects:
## (Intr)
## Days -0.371
Double check that the intercept for fixed effect is identical to the one we found earlier when we controlled for the subject. The coefficient for ‘Days’ reports the average effect of an extra day of sleep deprivation on reaction score.
Lets get to a bit more detailed output:
display(model_mix)
## lmer(formula = Reaction ~ Days + (1 | Subject), data = sleep)
## coef.est coef.se
## (Intercept) 251.41 9.75
## Days 10.47 0.80
##
## Error terms:
## Groups Name Std.Dev.
## Subject (Intercept) 37.12
## Residual 30.99
## ---
## number of obs: 180, groups: Subject, 18
## AIC = 1794.5, DIC = 1801.7
## deviance = 1794.1
We can extract fixed effect estimation:
fixef(model_mix)
## (Intercept) Days
## 251.40510 10.46729
se.fixef(model_mix)
## (Intercept) Days
## 9.7467163 0.8042214
Or random effect:
ranef(model_mix)
## $Subject
## (Intercept)
## 308 40.783710
## 309 -77.849554
## 310 -63.108567
## 330 4.406442
## 331 10.216189
## 332 8.221238
## 333 16.500494
## 334 -2.996981
## 335 -45.282127
## 337 72.182686
## 349 -21.196249
## 350 14.111363
## 351 -7.862221
## 352 36.378425
## 369 7.036381
## 370 -6.362703
## 371 -3.294273
## 372 18.115747
##
## with conditional variances for "Subject"
se.ranef(model_mix)
## $Subject
## (Intercept)
## 308 9.475668
## 309 9.475668
## 310 9.475668
## 330 9.475668
## 331 9.475668
## 332 9.475668
## 333 9.475668
## 334 9.475668
## 335 9.475668
## 337 9.475668
## 349 9.475668
## 350 9.475668
## 351 9.475668
## 352 9.475668
## 369 9.475668
## 370 9.475668
## 371 9.475668
## 372 9.475668
15.4.4 Partial Pooling (varying intercepts and/or slopes)
We can also vary slopes if we wanted to, we saw earlier that we may have very different line fit for reaction time for different individuals.
#Run the model (note thay we also control for the effect of time by subject)
model_mix_slope <- lmer(Reaction ~ Days + (Days|Subject) , sleep)
#Summarise
summary(model_mix_slope)
## Linear mixed model fit by REML ['lmerMod']
## Formula: Reaction ~ Days + (Days | Subject)
## Data: sleep
##
## REML criterion at convergence: 1743.6
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -3.9536 -0.4634 0.0231 0.4633 5.1793
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## Subject (Intercept) 611.90 24.737
## Days 35.08 5.923 0.07
## Residual 654.94 25.592
## Number of obs: 180, groups: Subject, 18
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 251.405 6.824 36.843
## Days 10.467 1.546 6.771
##
## Correlation of Fixed Effects:
## (Intr)
## Days -0.138
Each subject now will have their own slope estimation, which is as intercept is partially pooled towards the center of days effects distribution. Note the results for days coefficients in the main output.
Whatever decision you make, it will always be driven by your data. You may want to do model comparison and analysis the residuals in model output to see how much varying intercepts/slopes improved your understanding of underlying relationships in your data.
We can use log likelihood ratio test to compare the models we just built:
#Make sure lmtest is loaded
library(lmtest)
#Compare the null model with random intercept model
lrtest(model_null,model_mix)
## Likelihood ratio test
##
## Model 1: Reaction ~ (1 | Subject)
## Model 2: Reaction ~ Days + (1 | Subject)
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 3 -952.16
## 2 4 -893.23 1 117.86 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#Now varying intercept with both varying interecept + slopes
lrtest(model_mix, model_mix_slope)
## Likelihood ratio test
##
## Model 1: Reaction ~ Days + (1 | Subject)
## Model 2: Reaction ~ Days + (Days | Subject)
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 4 -893.23
## 2 6 -871.81 2 42.837 4.99e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
The model with random intercept improves on null model. Having a random slope and intercept improved the model even more.
We can also use something which is known pseudo R squared to see how much variance was explained due to our explanatory factor. We will need to calculate it by hand. We will use our model without controls where were have random intercepts and we will add days to compare the explained variation that is due to addition of explanatory factors. Just a reminder of the models we need:
model_null <- lmer(Reaction ~ (1|Subject) , sleep)
model_mix <- lmer(Reaction ~ Days + (1|Subject) , sleep)
## We can try to extract the partial variance that was explained by Days for mixed model
totvar_model_null <- (summary(model_null)$sigma)^2 + as.numeric(summary(model_null)$varcor)
totvar_model_mix <- (summary(model_mix)$sigma)^2 + as.numeric(summary(model_mix)$varcor)
Var_expl <-(totvar_model_null-totvar_model_mix)/totvar_model_null
Var_expl
## [1] 0.2775756
We find that about 28% of variation in reaction can be explained by time, when controlling for subjects.
Lets finally put all these models side by side:
#Make sure to have textreg loaded
library(texreg)
screenreg(list(model_null, model_mix))
##
## ==================================================
## Model 1 Model 2
## --------------------------------------------------
## (Intercept) 298.51 *** 251.41 ***
## (9.05) (9.75)
## Days 10.47 ***
## (0.80)
## --------------------------------------------------
## AIC 1910.33 1794.47
## BIC 1919.91 1807.24
## Log Likelihood -952.16 -893.23
## Num. obs. 180 180
## Num. groups: Subject 18 18
## Var: Subject (Intercept) 1278.34 1378.18
## Var: Residual 1958.87 960.46
## ==================================================
## *** p < 0.001, ** p < 0.01, * p < 0.05
15.5 Multilevel modelling with random intercepts and slopes
Multilevel models are used for cases where there are few levels to the measurement. A very common way to illustrate this is using students grades across schools that vary within the pupils at the school but also vary across schools. This is relevant in cases where grades were measure in different times as well.
For studies that look at this closely have a look at this review paper. The data set that we will work with has information on IQ scores for school students and is taken from Snijders and Bosker (2012) textbook. We will have different levels here, variability of grades within the schools and across the schools. What we want to understand is whether average score on languge test has anything to do with scores that student get in their SES and IQ and the scores at the average school level.
school: School id pupil: Student id lang_score: language score ses:Socioeconomic status of the student (mean centered) IQ_verb: Verbal IQ of the student (mean centered) sex: Gender of the student Minority: Dummy indicator of whether student is of minority background sch_ses: Average SES in a school (mean centered) sch_iqv: Average verbal IQ in a school (mean centered) sch_min: Proportion of minority students in a school
15.5.1 Prepare
Before we start let us load all the packages we will need later.
library(nlme)
library(lattice)
schools<-read.csv('schools.csv')
head(schools)
## school pupil lang_score ses IQ_verb sex Minority sch_ses sch_iqv
## 1 1 3 46 -4.73 3.13 0 0 -14.035 -1.4039
## 2 1 4 45 -17.73 2.63 0 1 -14.035 -1.4039
## 3 1 5 33 -12.73 -2.37 0 0 -14.035 -1.4039
## 4 1 6 46 -4.73 -0.87 0 0 -14.035 -1.4039
## 5 1 7 20 -17.73 -3.87 0 0 -14.035 -1.4039
## 6 1 8 30 -17.73 -2.37 0 1 -14.035 -1.4039
## sch_min
## 1 0.63
## 2 0.63
## 3 0.63
## 4 0.63
## 5 0.63
## 6 0.63
Let us first build a simple mixed effect model, we will try to predict language scores and will control for the school only:
model_schools_0 <- lmer(lang_score ~ (1|school), data = schools)
summary(model_schools_0)
## Linear mixed model fit by REML ['lmerMod']
## Formula: lang_score ~ (1 | school)
## Data: schools
##
## REML criterion at convergence: 26595.7
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -4.1850 -0.6417 0.0905 0.7226 2.5281
##
## Random effects:
## Groups Name Variance Std.Dev.
## school (Intercept) 18.24 4.271
## Residual 62.85 7.928
## Number of obs: 3758, groups: school, 211
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 41.0038 0.3257 125.9
We can also set up a NULL model, explained variance of which we will use to calculate pseudo R squared:
model_schools_null<- lm(lang_score ~1, data = schools)
summary(model_schools_null)
##
## Call:
## lm(formula = lang_score ~ 1, data = schools)
##
## Residuals:
## Min 1Q Median 3Q Max
## -33.413 -5.413 0.587 6.587 16.587
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 41.4130 0.1451 285.5 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 8.893 on 3757 degrees of freedom
We can quickly check whether having varying intercepts improves over having a single one for everyone:
lrtest(model_schools_null,model_schools_0)
## Likelihood ratio test
##
## Model 1: lang_score ~ 1
## Model 2: lang_score ~ (1 | school)
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 2 -13544
## 2 3 -13298 1 492.54 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Lets start adding some covariates, we can start with IQ and then see how much additional variance can be explained by the variable:
model_schools_IQ <- lmer(lang_score ~ IQ_verb + (1|school), data = schools, REML =FALSE)
summary(model_schools_IQ)
## Linear mixed model fit by maximum likelihood ['lmerMod']
## Formula: lang_score ~ IQ_verb + (1 | school)
## Data: schools
##
## AIC BIC logLik deviance df.resid
## 24920.2 24945.1 -12456.1 24912.2 3754
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -4.1963 -0.6385 0.0659 0.7098 3.2143
##
## Random effects:
## Groups Name Variance Std.Dev.
## school (Intercept) 9.845 3.138
## Residual 40.469 6.362
## Number of obs: 3758, groups: school, 211
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 41.05488 0.24339 168.68
## IQ_verb 2.50744 0.05438 46.11
##
## Correlation of Fixed Effects:
## (Intr)
## IQ_verb 0.003
Lets calculate variance of empty model, then with IQ:
totvar_model_0 <- (summary(model_schools_0)$sigma)^2 + as.numeric(summary(model_schools_0)$varcor)
totvar_model_IQ <- (summary(model_schools_IQ)$sigma)^2 + as.numeric(summary(model_schools_IQ)$varcor)
# Proportion of variance explained by IQ:
Rsq_IQ <- (totvar_model_0 - totvar_model_IQ)/totvar_model_0
Rsq_IQ
## [1] 0.3795199
On top of that, we can also make assessment of intraclass correlation (ICC), this will allow us to investigate whether there are systematic similarities in grades within the schools.
Lets get one for our first model:
ICC_0 <- as.numeric(summary(model_schools_0)$varcor)/((summary(model_schools_0)$sigma)^2 + as.numeric(summary(model_schools_0)$varcor))
ICC_0
## [1] 0.2249341
This tell us that about 22 percent of variation in language scores is at the school level. This can also be stated as the following: if we picked randomly two students that belong to the same school, we would expect about 0.22 correlation in their language scores.
ICC_IQ<-as.numeric(summary(model_schools_IQ)$varcor)/((summary(model_schools_IQ)$sigma)^2 + as.numeric(summary(model_schools_IQ)$varcor))
ICC_IQ
## [1] 0.1956726
We dropped to to 0.2 now, this tell us that once we look at the similarity of IQ scores at the school level, the correlation between the scores obtained on lang score can be explained by similarities in IQ scores within the school.
Finally, lets now add the schools average scores dynamic to our model:
model_schools_IQ_sc <- lmer(lang_score ~ IQ_verb + sch_iqv + (1|school), data = schools, REML =FALSE)
summary(model_schools_IQ_sc)
## Linear mixed model fit by maximum likelihood ['lmerMod']
## Formula: lang_score ~ IQ_verb + sch_iqv + (1 | school)
## Data: schools
##
## AIC BIC logLik deviance df.resid
## 24898.0 24929.2 -12444.0 24888.0 3753
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -4.2220 -0.6411 0.0634 0.7059 3.2190
##
## Random effects:
## Groups Name Variance Std.Dev.
## school (Intercept) 8.68 2.946
## Residual 40.43 6.358
## Number of obs: 3758, groups: school, 211
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 41.11378 0.23181 177.362
## IQ_verb 2.45361 0.05549 44.218
## sch_iqv 1.31242 0.26160 5.017
##
## Correlation of Fixed Effects:
## (Intr) IQ_vrb
## IQ_verb -0.007
## sch_iqv 0.043 -0.210
Try to get ICC and R squared by yourself here. You will find that controlling for average IQ in the school will improve model as well. We can thus incorporate the school levels on top of individual level of the final model and perform a likelihood ratio test.
model_school_final <- lmer(lang_score ~ IQ_verb + sch_iqv + (1+IQ_verb|school),
data = schools, REML =FALSE)
summary(model_school_final)
## Linear mixed model fit by maximum likelihood ['lmerMod']
## Formula: lang_score ~ IQ_verb + sch_iqv + (1 + IQ_verb | school)
## Data: schools
##
## AIC BIC logLik deviance df.resid
## 24878.9 24922.5 -12432.4 24864.9 3751
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -4.2615 -0.6335 0.0677 0.7033 2.7619
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## school (Intercept) 8.8783 2.9796
## IQ_verb 0.1949 0.4415 -0.63
## Residual 39.6855 6.2996
## Number of obs: 3758, groups: school, 211
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 41.12747 0.23363 176.036
## IQ_verb 2.47973 0.06429 38.569
## sch_iqv 1.02851 0.26221 3.923
##
## Correlation of Fixed Effects:
## (Intr) IQ_vrb
## IQ_verb -0.279
## sch_iqv -0.003 -0.188
lrtest(model_schools_IQ_sc, model_school_final)
## Likelihood ratio test
##
## Model 1: lang_score ~ IQ_verb + sch_iqv + (1 | school)
## Model 2: lang_score ~ IQ_verb + sch_iqv + (1 + IQ_verb | school)
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 5 -12444
## 2 7 -12432 2 23.149 9.404e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Finally, as usual by now, lets put everything side by side:
screenreg(list(model_schools_0, model_schools_IQ, model_schools_IQ_sc, model_school_final))
##
## ===========================================================================================
## Model 1 Model 2 Model 3 Model 4
## -------------------------------------------------------------------------------------------
## (Intercept) 41.00 *** 41.05 *** 41.11 *** 41.13 ***
## (0.33) (0.24) (0.23) (0.23)
## IQ_verb 2.51 *** 2.45 *** 2.48 ***
## (0.05) (0.06) (0.06)
## sch_iqv 1.31 *** 1.03 ***
## (0.26) (0.26)
## -------------------------------------------------------------------------------------------
## AIC 26601.69 24920.17 24898.02 24878.87
## BIC 26620.38 24945.09 24929.18 24922.49
## Log Likelihood -13297.84 -12456.08 -12444.01 -12432.44
## Num. obs. 3758 3758 3758 3758
## Num. groups: school 211 211 211 211
## Var: school (Intercept) 18.24 9.85 8.68 8.88
## Var: Residual 62.85 40.47 40.43 39.69
## Var: school IQ_verb 0.19
## Cov: school (Intercept) IQ_verb -0.83
## ===========================================================================================
## *** p < 0.001, ** p < 0.01, * p < 0.05
15.6 Random slopes, intercepts and cross level interactions (optional)
For this part we will use the dataset taken from Hox’s (2010) textbook on multilevel modelling. The dataset includes the following variables:
PUPIL : pupil id within class CLASS : class id (1,…,100) POPULAR : popularity score of the student SEX : sex of the student (0=male, 1=female) T.EXP : years of experience of the theacher
popularity<-read.csv('Popularity.csv')
We will go on straight to building our models, starting with null once again for later comparison.
model_null <- lm(POPULAR ~ 1, data = popularity)
model_pop_0 <- lmer(POPULAR ~ (1|CLASS), data = popularity)
summary(model_pop_0)
## Linear mixed model fit by REML ['lmerMod']
## Formula: POPULAR ~ (1 | CLASS)
## Data: popularity
##
## REML criterion at convergence: 5115.6
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.88825 -0.63376 -0.05155 0.71091 3.00393
##
## Random effects:
## Groups Name Variance Std.Dev.
## CLASS (Intercept) 0.8798 0.9380
## Residual 0.6387 0.7992
## Number of obs: 2000, groups: CLASS, 100
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 5.3076 0.0955 55.58
Tst whether random intercepts is an improvement:
lrtest(model_pop_0,model_null)
## Likelihood ratio test
##
## Model 1: POPULAR ~ (1 | CLASS)
## Model 2: POPULAR ~ 1
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 3 -2557.8
## 2 2 -3244.8 -1 1373.9 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Lets see whether gender has anything to do with popularity:
model_pop_sex <- lmer(POPULAR ~ FEMALE+(1|CLASS), data = popularity)
summary(model_pop_sex)
## Linear mixed model fit by REML ['lmerMod']
## Formula: POPULAR ~ FEMALE + (1 | CLASS)
## Data: popularity
##
## REML criterion at convergence: 4492.9
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -3.3184 -0.6892 0.0018 0.5961 3.8239
##
## Random effects:
## Groups Name Variance Std.Dev.
## CLASS (Intercept) 0.8622 0.9286
## Residual 0.4599 0.6782
## Number of obs: 2000, groups: CLASS, 100
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 4.89722 0.09530 51.39
## FEMALETRUE 0.84370 0.03096 27.25
##
## Correlation of Fixed Effects:
## (Intr)
## FEMALETRUE -0.158
## Pseudo R squared:
totvar_mod_pop_0 <- (summary(model_pop_0)$sigma)^2 + as.numeric(summary(model_pop_0)$varcor)
totvar_mod_pop_sex <- (summary(model_pop_sex)$sigma)^2 + as.numeric(summary(model_pop_sex)$varcor)
R_sq_pop <- (totvar_mod_pop_0 - totvar_mod_pop_sex)/totvar_mod_pop_0
R_sq_pop
## [1] 0.1293066
What about ICC?
as.numeric(summary(model_pop_sex)$varcor)/((summary(model_pop_sex)$sigma)^2 + as.numeric(summary(model_pop_sex)$varcor))
## [1] 0.652142
Lets add teching experience:
model_pop_teach <- lmer(POPULAR ~ FEMALE+T.EXP+(1|CLASS), data = popularity, REML =FALSE)
summary(model_pop_teach)
## Linear mixed model fit by maximum likelihood ['lmerMod']
## Formula: POPULAR ~ FEMALE + T.EXP + (1 | CLASS)
## Data: popularity
##
## AIC BIC logLik deviance df.resid
## 4438.6 4466.6 -2214.3 4428.6 1995
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -3.3598 -0.6806 0.0252 0.5945 3.7858
##
## Random effects:
## Groups Name Variance Std.Dev.
## CLASS (Intercept) 0.4758 0.6898
## Residual 0.4597 0.6780
## Number of obs: 2000, groups: CLASS, 100
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 3.56066 0.16977 20.974
## FEMALETRUE 0.84471 0.03094 27.300
## T.EXP 0.09345 0.01074 8.697
##
## Correlation of Fixed Effects:
## (Intr) FEMALE
## FEMALETRUE -0.089
## T.EXP -0.905 0.000
Lets check whether there is an imrprovement:
totvar_mod_pop_0 <- (summary(model_pop_0)$sigma)^2 + as.numeric(summary(model_pop_0)$varcor)
totvar_mod_teach <- (summary(model_pop_teach)$sigma)^2 + as.numeric(summary(model_pop_teach)$varcor)
Rsq_teach <- (totvar_mod_pop_0 - totvar_mod_teach/totvar_mod_pop_0 )
Rsq_teach
## [1] 0.9024452
Teacher experience plus sex of the student explain an etra chunk of variability in popularity. Does this effect varies across the schools, explore the following model yourself:
model_teach_sc <- lmer(POPULAR ~ FEMALE+T.EXP+(1+FEMALE|CLASS), data = popularity)
Run test to see if there are any differences:
lrtest(model_pop_teach,model_teach_sc)
## Likelihood ratio test
##
## Model 1: POPULAR ~ FEMALE + T.EXP + (1 | CLASS)
## Model 2: POPULAR ~ FEMALE + T.EXP + (1 + FEMALE | CLASS)
## #Df LogLik Df Chisq Pr(>Chisq)
## 1 5 -2214.3
## 2 7 -2137.9 2 152.68 < 2.2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Finally, lets add an interaction:
model_pop_interaction <- lmer(POPULAR ~ FEMALE*T.EXP+(1+FEMALE|CLASS), data = popularity, REML =FALSE)
## Warning in checkConv(attr(opt, "derivs"), opt$par, ctrl =
## control$checkConv, : Model failed to converge with max|grad| = 0.00219266
## (tol = 0.002, component 1)
summary(model_pop_interaction)
## Linear mixed model fit by maximum likelihood ['lmerMod']
## Formula: POPULAR ~ FEMALE * T.EXP + (1 + FEMALE | CLASS)
## Data: popularity
##
## AIC BIC logLik deviance df.resid
## 4261.8 4306.7 -2122.9 4245.8 1992
##
## Scaled residuals:
## Min 1Q Median 3Q Max
## -2.9339 -0.6473 0.0230 0.5327 3.4915
##
## Random effects:
## Groups Name Variance Std.Dev. Corr
## CLASS (Intercept) 0.4029 0.6348
## FEMALETRUE 0.2201 0.4692 0.08
## Residual 0.3924 0.6264
## Number of obs: 2000, groups: CLASS, 100
##
## Fixed effects:
## Estimate Std. Error t value
## (Intercept) 3.313652 0.159395 20.789
## FEMALETRUE 1.329478 0.131689 10.096
## T.EXP 0.110229 0.010129 10.882
## FEMALETRUE:T.EXP -0.034025 0.008371 -4.065
##
## Correlation of Fixed Effects:
## (Intr) FEMALETRUE T.EXP
## FEMALETRUE -0.046
## T.EXP -0.909 0.042
## FEMALETRUE: 0.042 -0.908 -0.046
## convergence code: 0
## Model failed to converge with max|grad| = 0.00219266 (tol = 0.002, component 1)
Find the change in explained variance by yourself here.
Finally, put all side by side:
screenreg(list( model_pop_sex, model_pop_teach, model_teach_sc, model_pop_interaction))
##
## =========================================================================================
## Model 1 Model 2 Model 3 Model 4
## -----------------------------------------------------------------------------------------
## (Intercept) 4.90 *** 3.56 *** 3.34 *** 3.31 ***
## (0.10) (0.17) (0.16) (0.16)
## FEMALETRUE 0.84 *** 0.84 *** 0.84 *** 1.33 ***
## (0.03) (0.03) (0.06) (0.13)
## T.EXP 0.09 *** 0.11 *** 0.11 ***
## (0.01) (0.01) (0.01)
## FEMALETRUE:T.EXP -0.03 ***
## (0.01)
## -----------------------------------------------------------------------------------------
## AIC 4500.89 4438.57 4289.89 4261.85
## BIC 4523.30 4466.58 4329.10 4306.66
## Log Likelihood -2246.45 -2214.29 -2137.95 -2122.92
## Num. obs. 2000 2000 2000 2000
## Num. groups: CLASS 100 100 100 100
## Var: CLASS (Intercept) 0.86 0.48 0.41 0.40
## Var: Residual 0.46 0.46 0.39 0.39
## Var: CLASS FEMALETRUE 0.27 0.22
## Cov: CLASS (Intercept) FEMALETRUE 0.02 0.02
## =========================================================================================
## *** p < 0.001, ** p < 0.01, * p < 0.05