##Here we present some simple mixed model examples in a simulated dataset

First we will set a seed for reproducibility. We have selected this one because it produces a clear plot. Feel free to change the seed and see how the outcome changes

set.seed(20)

We now load the packages we need

#libraries
library(nlme)
library(lme4)

Now we simulate the data we will fit models too

#random effect groups
clones<-6
#number of samples per random effect group
perclone<-20
clone<-gl(clones,perclone)
#categorical explanatory variable
treat<-rep(gl(2,perclone/2),clones)
treat<-as.numeric(treat)-1
#continuous explanatory variable (covariate)
treat.cov<-runif(clones*perclone,0,1)

#2 response variables - one for the categorical explanatory variable and one for the covariate
y.mean<-rep(rnorm(clones,0,1),each=perclone)
y.slope<-rep(rnorm(clones,0,0.5),each=perclone)
y.obs<-rnorm(perclone*clones,y.mean+treat+y.slope*treat,0.5)
y.obs.cov<-y.obs-y.slope*treat-treat+(1+y.slope)*treat.cov


We now fit the random intercepts versions of the models using nlme

#random intercept, treatment model
m1.rint<-lme(y.obs~treat,random=~1|clone, control = lmeControl(opt = "optim"))
summary(m1.rint)
## Linear mixed-effects model fit by REML
##  Data: NULL 
##        AIC      BIC    logLik
##   224.9004 235.9831 -108.4502
## 
## Random effects:
##  Formula: ~1 | clone
##         (Intercept)  Residual
## StdDev:    1.172938 0.5316437
## 
## Fixed effects: y.obs ~ treat 
##                  Value Std.Error  DF   t-value p-value
## (Intercept) -0.2931516 0.4837438 113 -0.606006  0.5457
## treat        1.1407645 0.0970644 113 11.752654  0.0000
##  Correlation: 
##       (Intr)
## treat -0.1  
## 
## Standardized Within-Group Residuals:
##        Min         Q1        Med         Q3        Max 
## -2.3794186 -0.6752965  0.1082650  0.6576496  2.3083782 
## 
## Number of Observations: 120
## Number of Groups: 6
#random intercept covariate model
m1.rintcov<-lme(y.obs.cov~treat.cov,random=~1|clone, control = lmeControl(opt = "optim"))
summary(m1.rintcov)
## Linear mixed-effects model fit by REML
##  Data: NULL 
##        AIC      BIC    logLik
##   208.2389 219.3217 -100.1195
## 
## Random effects:
##  Formula: ~1 | clone
##         (Intercept)  Residual
## StdDev:    1.174101 0.4961598
## 
## Fixed effects: y.obs.cov ~ treat.cov 
##                  Value Std.Error  DF   t-value p-value
## (Intercept) -0.0355387 0.4874938 113 -0.072901  0.9420
## treat.cov    0.6133837 0.1534115 113  3.998290  0.0001
##  Correlation: 
##           (Intr)
## treat.cov -0.157
## 
## Standardized Within-Group Residuals:
##         Min          Q1         Med          Q3         Max 
## -2.33587731 -0.64669678  0.02352256  0.61664940  2.05224191 
## 
## Number of Observations: 120
## Number of Groups: 6

We now fit the random slopes versions of the models using nlme

#random slope, treatment model
m1.rslope<-lme(y.obs~treat,random=~treat|clone, control = lmeControl(opt = "optim"))
summary(m1.rslope)
## Linear mixed-effects model fit by REML
##  Data: NULL 
##        AIC      BIC    logLik
##   217.0846 233.7087 -102.5423
## 
## Random effects:
##  Formula: ~treat | clone
##  Structure: General positive-definite, Log-Cholesky parametrization
##             StdDev    Corr  
## (Intercept) 1.0720340 (Intr)
## treat       0.4404704 0.382 
## Residual    0.4896137       
## 
## Fixed effects: y.obs ~ treat 
##                  Value Std.Error  DF   t-value p-value
## (Intercept) -0.2931516 0.4421970 113 -0.662943  0.5087
## treat        1.1407645 0.2008144 113  5.680692  0.0000
##  Correlation: 
##       (Intr)
## treat 0.293 
## 
## Standardized Within-Group Residuals:
##          Min           Q1          Med           Q3          Max 
## -2.249516136 -0.673480190  0.004823643  0.703378061  2.114185365 
## 
## Number of Observations: 120
## Number of Groups: 6
ranef(m1.rslope)
##   (Intercept)      treat
## 1   0.4725388  0.4082560
## 2   0.2751279 -0.4549530
## 3  -0.1686910  0.3879957
## 4  -0.7709775 -0.4163447
## 5   1.6298310  0.2514858
## 6  -1.4378293 -0.1764398
fixef(m1.rslope)
## (Intercept)       treat 
##  -0.2931516   1.1407645
#random slope covariate model
m1.rslopecov<-lme(y.obs.cov~treat.cov,random=~treat.cov|clone, control = lmeControl(opt = "optim"))
summary(m1.rslopecov)
## Linear mixed-effects model fit by REML
##  Data: NULL 
##        AIC      BIC    logLik
##   209.6554 226.2795 -98.82768
## 
## Random effects:
##  Formula: ~treat.cov | clone
##  Structure: General positive-definite, Log-Cholesky parametrization
##             StdDev    Corr  
## (Intercept) 1.1079246 (Intr)
## treat.cov   0.4116194 0.249 
## Residual    0.4827630       
## 
## Fixed effects: y.obs.cov ~ treat.cov 
##                  Value Std.Error  DF    t-value p-value
## (Intercept) -0.0369545 0.4606034 113 -0.0802305  0.9362
## treat.cov    0.6107964 0.2251688 113  2.7126153  0.0077
##  Correlation: 
##           (Intr)
## treat.cov 0.075 
## 
## Standardized Within-Group Residuals:
##         Min          Q1         Med          Q3         Max 
## -2.16873970 -0.66078372  0.05075708  0.75091755  2.09459239 
## 
## Number of Observations: 120
## Number of Groups: 6
ranef(m1.rslopecov)
##   (Intercept)    treat.cov
## 1   0.5242008  0.295154222
## 2   0.2215720 -0.340176948
## 3  -0.1441830  0.254298446
## 4  -0.7619135 -0.431431787
## 5   1.6704060  0.219866382
## 6  -1.5100822  0.002289684
fixef(m1.rslopecov)
## (Intercept)   treat.cov 
## -0.03695446  0.61079645


We now plot the data and our model predictions to demonstrate the difference between the random intercepts and random slopes models

#set colour scheme for plots
cols<-c("#332288", "#88CCEE", "#117733", "#DDCC77", "#CC6677","#AA4499")

#plotting
par(mfrow=c(2,2),mar=c(3,3,1,1))

plot(y.obs~treat,type="n",xlab="",ylab="",xlim=c(-0.05,1.05),xaxt="n",las=1)
axis(side=1,at=c(0,1))
mtext(side=1,line=2,"Treatment")
mtext(side=2,line=2,"Response")
for(i in 1:clones){
  lines(c(0,1),c(fixef(m1.rint)[1]+ranef(m1.rint)[i,1],fixef(m1.rint)[1]+ranef(m1.rint)[i,1]+fixef(m1.rint)[2]*1),lwd=2,col=cols[i])}
for(i in 1:clones){
  treat.plot<-treat+i/50-0.06
  points(y.obs~treat.plot,subset=(clone==i),pch=21,cex=1.5,bg=cols[i])}
lines(c(0,1),c(fixef(m1.rint)[1],fixef(m1.rint)[1]+fixef(m1.rint)[2]*1),lwd=3,col="black",lty=2)

plot(y.obs~treat,type="n",xlab="",ylab="",xlim=c(-0.05,1.05),xaxt="n",las=1)
axis(side=1,at=c(0,1))
mtext(side=1,line=2,"Treatment")
mtext(side=2,line=2,"Response")
for(i in 1:clones){
  lines(c(0,1),c(fixef(m1.rslope)[1]+ranef(m1.rslope)[i,1],fixef(m1.rslope)[1]+ranef(m1.rslope)[i,1]+(fixef(m1.rslope)[2]+ranef(m1.rslope)[i,2])*1),lwd=2,col=cols[i])}
for(i in 1:clones){
  treat.plot<-treat+i/50-0.06
  points(y.obs~treat.plot,subset=(clone==i),pch=21,cex=1.5,bg=cols[i])}
lines(c(0,1),c(fixef(m1.rslope)[1],fixef(m1.rslope)[1]+fixef(m1.rslope)[2]*1),lwd=3,col="black",lty=2)

plot(y.obs.cov~treat.cov,type="n",xlab="",ylab="",xlim=c(-0.05,1.05),las=1)
mtext(side=1,line=2,"Covariate")
mtext(side=2,line=2,"Response")
treat.plot<-treat.cov
for(i in 1:clones){
  lines(c(0,1),c(fixef(m1.rintcov)[1]+ranef(m1.rintcov)[i,1],fixef(m1.rintcov)[1]+ranef(m1.rintcov)[i,1]+fixef(m1.rintcov)[2]*1),lwd=2,col=cols[i])}
for(i in 1:clones){
  points(y.obs.cov~treat.plot,subset=(clone==i),pch=21,cex=1.5,bg=cols[i])}
lines(c(0,1),c(fixef(m1.rintcov)[1],fixef(m1.rintcov)[1]+fixef(m1.rintcov)[2]*1),lwd=3,col="black",lty=2)

plot(y.obs.cov~treat.cov,type="n",xlab="",ylab="",xlim=c(-0.05,1.05),las=1)
mtext(side=1,line=2,"Covariate")
mtext(side=2,line=2,"Response")
for(i in 1:clones){
  lines(c(0,1),c(fixef(m1.rslopecov)[1]+ranef(m1.rslopecov)[i,1],fixef(m1.rslopecov)[1]+ranef(m1.rslopecov)[i,1]+(fixef(m1.rslopecov)[2]+ranef(m1.rslopecov)[i,2])*1),lwd=2,col=cols[i])}
for(i in 1:clones){
  treat.plot<-treat.cov+i/50-0.06
  points(y.obs.cov~treat.plot,subset=(clone==i),pch=21,cex=1.5,bg=cols[i])}
lines(c(0,1),c(fixef(m1.rslopecov)[1],fixef(m1.rslopecov)[1]+fixef(m1.rslopecov)[2]*1),lwd=3,col="black",lty=2)