# Introductory demo of additive models # After an example in Simon N. Wood, _Generalized Additve Models: An # Introduction with R_, chapter 5. # Load one of the two libraries for additive models require(mgcv) # Load package and data set require(gamair); data(chicago) # Peek at the data head(chicago) # For visualization, it will help to know what time==0 actually means day.zero <- as.Date("1993-12-31") # Add a column with the date # Why not cbind() here? chicago$date <- chicago$time+day.zero # Plot the data: deaths vs. time plot(chicago$time+day.zero,chicago$death,xlab="date",ylab="deaths per day", pch=16,cex=0.3) # Or: ### plot(death ~ date, data=chicago, ylab="deaths per day",pch=16,cex=0.3) # Fit a smoothing spline smooth.death <- smooth.spline(x=chicago$time,y=chicago$death) # Add spline to plot lines(chicago$date,smooth.death$y,col="red",lwd=4) # RMSE (in sample), RMSE (cross-validated), and two versions of R^2 sqrt(mean(residuals(smooth.death)^2)) # In-sample root MSE sqrt(smooth.death$cv.crit) # Cross-validated root MSE (cor(smooth.death$y,chicago$death))^2 # R^2, take 1 var(smooth.death$y)/var(chicago$death) # R^2, take 2 plot(fitted(smooth.death),residuals(smooth.death),pch=16,cex=0.3) abline(h=0,col="grey",lwd=3) # Form running averages over lagging windows # Exercise: Re-write to eliminate the for loop lag.mean <- function(x, window) { n <- length(x) y <- rep(0,n-window) # If we're using a loop, pre-allocate the final object for (t in 0:window) { y <- y + x[(t+1):(n-window+t)] } return(y/(window+1)) } chicago.avg <- chicago[-(1:3),c("death","time","date")] pollution.and.temp <- apply(chicago[,c(2,4,5,7)],2,lag.mean,window=3) chicago.avg <- data.frame(chicago.avg,pollution.and.temp) # Why don't we take running averages of deaths and time? # Fit an additive model, excluding date/time as a predictor require(mgcv) chicago.gam.0 <- gam(death~s(so2median)+s(pm10median) +s(tmpd)+s(o3median), data=chicago.avg,na.action=na.exclude) # Plot the partial response functions plot(chicago.gam.0,select=1, xlab="Concentration of sulfur dioxide (deviation from baseline)", ylab="Predicted change in deaths per day") plot(chicago.gam.0,select=2, xlab="Concentration of smaller particulates (deviation from baseline)", ylab="Predicted change in deaths per day") plot(chicago.gam.0,select=3, xlab="Temperature (Fahrenheit)", ylab="Predicted change in deaths per day") plot(chicago.gam.0,select=4, xlab="Concentration of ozone (deviation from baseline)", ylab="Predicted change in deaths per day") # Plot over time plot(death~date,data=chicago,ylab="deaths per day",pch=16,cex=0.3) lines(chicago$date,smooth.death$y,col="red",lwd=8) lines(chicago.avg$date,fitted(chicago.gam.0),col="blue",lwd=4) plot(fitted(chicago.gam.0),residuals(chicago.gam.0),xlab="Predicted", ylab="Residuals",pch=16,cex=0.3) abline(h=0,col="grey",lwd=3) # Fit additive model, excluding date as a predictor but interacting # temperature and ozone chicago.gam.1 <- gam(death~s(so2median) +s(pm10median) +s(tmpd,o3median), data=chicago.avg,na.action=na.exclude) # Plot partial response functions plot(chicago.gam.1,select=1, xlab="Concentration of sulfur dioxide [deviation from baseline]", ylab="Predicted change in deaths per day") plot(chicago.gam.1,select=2, xlab="Concentration of particulates [deviation from baseline]", ylab="Predicted change in deaths per day") plot(chicago.gam.1,select=3,xlab="Temperature (Fahrenheit)", ylab="Concentration of ozone [deviation from baseline]", se=FALSE,scheme=0,rug=FALSE) # Plot over time plot(death~date,data=chicago,ylab="deaths per day",pch=16,cex=0.3) lines(chicago$date,smooth.death$y,col="red",lwd=4) lines(chicago.avg$date,fitted(chicago.gam.0),col="blue") lines(chicago.avg$date,fitted(chicago.gam.1),col="orange")