> #obtain data
> inverts<- read.table('http://www.unc.edu/courses/2006spring/ecol/145/001/data/lab11/74species.csv', sep=',', header=TRUE)
> names(inverts)
[1] "species" "meantemp" "temp" "PLD" "taxon" "climate.3"
[7] "feeding.type" "lntemp" "lnPLD" "n" "PLD.15c" "lnPLD.15c"
[13] "X1000.k" "lograte"
> library(nlme)
> modelOLS<-lm(lnPLD~lntemp, data=inverts)
> model0<-lme(lnPLD~1,random=~1|species, data=inverts, method='ML')
> model1<-lme(lnPLD~lntemp, random=~1|species, data=inverts, method='ML')
> model2<-lme(lnPLD~lntemp, random=~lntemp|species, data=inverts, method='ML')
> mod.names<-c('OLS', 'uncond. mean', 'random ints', 'random ints/slopes')
> mod.aic<-sapply(list(modelOLS, model0, model1, model2), AIC)
> data.frame(mod.names, mod.aic)
mod.names mod.aic
1 OLS 553.0685
2 uncond. mean 451.2372
3 random ints 239.5597
4 random ints/slopes 210.4372
The remaining parameter
is not shown.


Fig. 1 The OLS model and the three basic multilevel models for the larval development data set.
> table(inverts$climate.3)
polar temperate tropical
29 152 37
> table(tapply(inverts$climate.3, inverts$species, function(x) x[1]))
1 2 3
8 53 13
> contrasts(inverts$climate.3)
temperate tropical
polar 0 0
temperate 1 0
tropical 0 1
Does climate.3 affect the population intercept?


> model3<-lme(lnPLD~lntemp+climate.3, random=~lntemp|species, data=inverts, method='ML')
Error in solve.default(pdMatrix(a, fact = TRUE)) :
system is computationally singular: reciprocal condition number = 1.26964e-053
> model3<-lme(lnPLD~I(lntemp-mean(lntemp))+climate.3, random=~I(lntemp-mean(lntemp))|species, data=inverts, method='ML')
The model now converges.
> mean(inverts$lntemp)
[1] 2.809248
> exp(mean(inverts$lntemp))
[1] 16.59743
> model3<-lme(lnPLD~I(lntemp-log(15))+climate.3,random=~I(lntemp-log(15))|species,data=inverts, method='ML')
> summary(model3)
Linear mixed-effects model fit by maximum likelihood
Data: inverts
AIC BIC logLik
213.8831 240.9590 -98.94154Random effects:
Formula: ~I(lntemp - log(15)) | species
Structure: General positive-definite, Log-Cholesky parametrization
StdDev Corr
(Intercept) 0.9099084 (Intr)
I(lntemp - log(15)) 0.5313982 -0.456
Residual 0.1519110Fixed effects: lnPLD ~ I(lntemp - log(15)) + climate.3
Value Std.Error DF t-value p-value
(Intercept) 2.9544791 0.3136574 143 9.419446 0.0000
I(lntemp - log(15)) -1.4529806 0.0852620 143 -17.041368 0.0000
climate.3temperate 0.1940039 0.3313066 71 0.585572 0.5600
climate.3tropical 0.3081079 0.3860982 71 0.798004 0.4275
Correlation:
(Intr) I(-l(1 clmt.3tm
I(lntemp - log(15)) -0.160
climate.3temperate -0.925 0.019
climate.3tropical -0.791 -0.004 0.749Standardized Within-Group Residuals:
Min Q1 Med Q3 Max
-2.50718336 -0.36428146 -0.01874458 0.40493293 3.66881543Number of Observations: 218
Number of Groups: 74
> anova(model2,model3)
Model df AIC BIC logLik Test L.Ratio p-value
model2 1 6 210.4372 230.7441 -99.21859
model3 2 8 213.8831 240.9590 -98.94154 1 vs 2 0.554096 0.758
> model2.5<-lme(lnPLD~I(lntemp-log(15)), random=~I(lntemp-log(15))|species, data=inverts, method='ML')
> VarCorr(model2.5)
species = pdLogChol(I(lntemp - log(15)))
Variance StdDev Corr
(Intercept) 0.85672246 0.9255930 (Intr)
I(lntemp - log(15)) 0.28109623 0.5301851 -0.49
Residual 0.02310587 0.1520062
> VarCorr(model3)
species = pdLogChol(I(lntemp - log(15)))
Variance StdDev Corr
(Intercept) 0.82793327 0.9099084 (Intr)
I(lntemp - log(15)) 0.28238407 0.5313982 -0.456
Residual 0.02307696 0.1519110

> (as.numeric(VarCorr(model2.5)[1,1]) - as.numeric(VarCorr(model3)[1,1])) / as.numeric(VarCorr(model2.5)[1,1])
[1] 0.03360387So only 3% of the species-level variation in the intercepts is explained by climate. This is consistent with the fact that adding climate.3 to the level-2 equation for the intercept did not significantly improve the model.
> anova(model2.5,model3)
Model df AIC BIC logLik Test L.Ratio p-value
model2.5 1 6 210.4372 230.7441 -99.21859
model3 2 8 213.8831 240.9590 -98.94154 1 vs 2 0.554096 0.758
Does climate.3 affect the population slope?

or in composite form
> model4<-lme(lnPLD~I(lntemp-log(15)) + I(lntemp-log(15)):climate.3, random=~I(lntemp-log(15))|species, data=inverts, method='ML')
> anova(model4,model2)
Model df AIC BIC logLik Test L.Ratio p-value
model4 1 8 206.7896 233.8655 -95.39479
model2 2 6 210.4372 230.7441 -99.21859 1 vs 2 7.647598 0.0218
> VarCorr(model4)
species = pdLogChol(I(lntemp - log(15)))
Variance StdDev Corr
(Intercept) 0.86149947 0.9281700 (Intr)
I(lntemp - log(15)) 0.20631864 0.4542231 -0.453
Residual 0.02314854 0.1521464
> VarCorr(model2.5)
species = pdLogChol(I(lntemp - log(15)))
Variance StdDev Corr
(Intercept) 0.85672246 0.9255930 (Intr)
I(lntemp - log(15)) 0.28109623 0.5301851 -0.49
Residual 0.02310587 0.1520062
> VarCorr(model2.5)[2,1]
[1] "0.28109623"
> (as.numeric(VarCorr(model2.5)[2,1]) - as.numeric(VarCorr(model4)[2,1])) / as.numeric(VarCorr(model2.5)[2,1])
[1] 0.2660213So 26.6% of the variability in slopes between species is explained by climate.3.
Does climate.3 affect the population slopes and intercepts?

or in composite form
fixed=lnPLD~I(lntemp-log(15))+climate.3+I(lntemp-log(15)):climate.3
or using R's shortcut notation
fixed=lnPLD~I(lntemp-log(15))*climate.3
where the * notation automatically generates all three terms (plus the intercept).
> model5<-lme(lnPLD~I(lntemp-log(15))*climate.3, random=~I(lntemp-log(15))|species, data=inverts, method='ML')
> anova(model5,model2)
Model df AIC BIC logLik Test L.Ratio p-value
model5 1 10 206.4266 240.2715 -93.21330
model2 2 6 210.4372 230.7441 -99.21859 1 vs 2 12.01058 0.0173
> anova(model5,model4)
Model df AIC BIC logLik Test L.Ratio p-value
model5 1 10 206.4266 240.2715 -93.21330
model4 2 8 206.7896 233.8655 -95.39479 1 vs 2 4.362981 0.1129
> sapply(list(model2,model3,model4,model5),AIC)
[1] 210.4372 213.8831 206.7896 206.4266
> fixef(model4)
(Intercept) I(lntemp - log(15))
3.1724449 -1.0277108
I(lntemp - log(15)):climate.3temperate I(lntemp - log(15)):climate.3tropical
-0.4736086 -0.7131552Observe that as we move from polar to temperate to tropical the slope becomes more negative.
![]()
where
and
are dummy variables created by R. Using the contrasts defined for these variables we can write the slope equations for the three regions.

> polar.func<-function(x) fixef(model4)[1] + fixef(model4)[2]*(x-log(15))
> temp.func<-function(x) fixef(model4)[1] + (fixef(model4)[2] + fixef(model4)[3])*(x-log(15))
> trop.func<-function(x) fixef(model4)[1] + (fixef(model4)[2] + fixef(model4)[4])*(x-log(15))
> plot(inverts$lntemp,inverts$lnPLD, type='n', xlab='log(temperature) ', ylab='log(PLD) ')
> lines(log(seq(2,42,10)), polar.func(log(seq(2,42,10))), col=1)
> lines(log(seq(2,42,10)), temp.func(log(seq(2,42,10))), col=2)
> lines(log(seq(2,42,10)), trop.func(log(seq(2,42,10))), col=3)
> legend(1,1.5,c('polar','temperate','tropic'), lty=c(1,1,1), col=c(1,2,3), bty='n', cex=c(.8,.8,.8))
> mtext('Marginal model: climate affects the slope', side=3, line=.5)
![]()
Fig. 2 Effect of climate on population-averaged model
| Jack Weiss Phone: (919) 962-5930 E-Mail: jack_weiss@unc.edu Address: Curriculum in Ecology, Box 3275, University of North Carolina, Chapel Hill, 27516 Copyright © 2006 Last Revised--April 10, 2006 URL: http://www.unc.edu/courses/2006spring/ecol/145/001/docs/lectures/lecture44.htm |