We examine the "International Airline Passengers" data from Box and Jenkins' book, referred to as airline for short. The data covers a span from January 1949 through December 1960, and exhibits trend and seasonality.
This code installs and loads the packages, and loads the data into a variable named airline.
library(devtools) library(Rcpp) devtools::install_github("tuckermcelroy/sigex") library(sigex) airline <- c(112, 118, 132, 129, 121, 135, 148, 148, 136, 119, 104, 118, 115, 126, 141, 135, 125, 149, 170, 170, 158, 133, 114, 140, 145, 150, 178, 163, 172, 178, 199, 199, 184, 162, 146, 166, 171, 180, 193, 181, 183, 218, 230, 242, 209, 191, 172, 194, 196, 196, 236, 235, 229, 243, 264, 272, 237, 211, 180, 201, 204, 188, 235, 227, 234, 264, 302, 293, 259, 229, 203, 229, 242, 233, 267, 269, 270, 315, 364, 347, 312, 274, 237, 278, 284, 277, 317, 313, 318, 374, 413, 405, 355, 306, 271, 306, 315, 301, 356, 348, 355, 422, 465, 467, 404, 347, 305, 336, 340, 318, 362, 348, 363, 435, 491, 505, 404, 359, 310, 337, 360, 342, 406, 396, 420, 472, 548, 559, 463, 407, 362, 405, 417, 391, 419, 461, 472, 535, 622, 606, 508, 461, 390, 432)
start.time <- c(1949,1) period <- 12
dataALL.ts <- sigex.load(as.matrix(airline),start.time,period, c("Airline"),TRUE)
transform <- "log" aggregate <- FALSE subseries <- 1 range <- NULL end.time <- end(dataALL.ts) data.ts <- sigex.prep(dataALL.ts,transform,aggregate,subseries,range,TRUE)
# raw data par(mfrow=c(1,1)) for(i in 1:length(subseries)) { sigex.specar(data.ts,FALSE,i,period) }
# growth rates par(mfrow=c(1,1)) for(i in 1:length(subseries)) { sigex.specar(data.ts,TRUE,i,period) }
N <- dim(data.ts)[2] T <- dim(data.ts)[1]
start.date <- c(start.time[2],1,start.time[1]) if(end.time[2] == 12) { end.day <- 31 } else { end.day <- date2day(end.time[2]+1,1,end.time[1]) - date2day(end.time[2],1,end.time[1]) } end.date <- c(end.time[2],end.day,end.time[1])
td.weights <- NULL for(i in 1:7) { td.weights <- cbind(td.weights,daily2monthly(rep(1,T*35),start.date,i)[,1]) } td.weights <- td.weights[1:T,2:7] - td.weights[1:T,1]
easter.path <- system.file('extdata','easter500.txt',package='sigex') easter.dates <- read.table(easter.path) easter.reg <- gethol(easter.dates,1,0,start.date,end.date)
easter.regs <- NULL for(i in 1:7) { easter.regs <- cbind(easter.regs,daily2monthly(easter.reg,start.date,i)[,1]) } easter.regs <- rowSums(easter.regs)
delta.seas <- c(1,-1,rep(0,period-2),-1,1) mdl <- NULL mdl <- sigex.add(mdl,seq(1,N),"sarma",c(0,1,0,1,12),NULL,"process",delta.seas) mdl <- sigex.meaninit(mdl,data.ts,0) mdl <- sigex.reg(mdl,1,ts(td.weights[,1,drop=FALSE],start=start.time, frequency=period,names="TD Monday")) mdl <- sigex.reg(mdl,1,ts(td.weights[,2,drop=FALSE],start=start.time, frequency=period,names="TD Tuesday")) mdl <- sigex.reg(mdl,1,ts(td.weights[,3,drop=FALSE],start=start.time, frequency=period,names="TD Wednesday")) mdl <- sigex.reg(mdl,1,ts(td.weights[,4,drop=FALSE],start=start.time, frequency=period,names="TD Thursday")) mdl <- sigex.reg(mdl,1,ts(td.weights[,5,drop=FALSE],start=start.time, frequency=period,names="TD Friday")) mdl <- sigex.reg(mdl,1,ts(td.weights[,6,drop=FALSE],start=start.time, frequency=period,names="TD Saturday")) mdl <- sigex.reg(mdl,1,ts(as.matrix(easter.regs),start=start.time, frequency=period,names="Easter"))
constraint <- NULL constraint <- rbind(constraint, sigex.constrainreg(mdl,data.ts,list(seq(2,6)),NULL)) par.mle <- sigex.default(mdl,data.ts,constraint) psi.mle <- sigex.par2psi(par.mle,mdl) fit.mle <- sigex.mlefit(data.ts,par.mle,constraint,mdl,"bfgs",debug=FALSE) psi.mle <- sigex.eta2psi(fit.mle[[1]]$par,constraint) hess <- fit.mle[[1]]$hessian par.mle <- fit.mle[[2]]
r sigex.lik(psi.mle,mdl,data.ts)
.print(eigen(hess)$values)
resid.mle <- sigex.resid(psi.mle,mdl,data.ts)[[1]] resid.mle <- sigex.load(t(resid.mle),start(data.ts), frequency(data.ts),colnames(data.ts),TRUE) resid.acf <- acf(resid.mle,lag.max=4*period,plot=TRUE)$acf
analysis.mle <- sigex.bundle(data.ts,transform,mdl,psi.mle)
airlineDecomp <- function(theta) { # function to compute canonical decomposition for given airline model # input: theta has nonseasonal theta and seasonal theta, in Box-Jenkins notation # output: trendirreg is two moving average parameters, # and innovation variance for nonseasonal # seasonal is eleven moving average parameters, # and innovation variance for seasonal # Requires: polymult.r, specFact.r temp <- polymult(c(1,-1*theta[1]),c(1,rep(0,11),-1*theta[2])) gamma <- polymult(temp,rev(temp))[14:27] # Compute partial fraction decomposition Amat <- matrix(0,nrow=14,ncol=14) Amat[,1] <- c(12,11,10,9,8,7,6,5,4,3,2,1,0,0) Amat[,2] <- c(22,22,20,18,16,14,12,10,8,6,4,2,1,0) Amat[,3] <- c(6,-4,1,rep(0,11)) Amat[,4] <- c(-8,7,-4,1,rep(0,10)) Amat[,5] <- c(2,-4,6,-4,1,rep(0,9)) Amat[,6] <- c(0,1,-4,6,-4,1,rep(0,8)) Amat[,7] <- c(0,0,1,-4,6,-4,1,rep(0,7)) Amat[,8] <- c(rep(0,3),1,-4,6,-4,1,rep(0,6)) Amat[,9] <- c(rep(0,4),1,-4,6,-4,1,rep(0,5)) Amat[,10] <- c(rep(0,5),1,-4,6,-4,1,rep(0,4)) Amat[,11] <- c(rep(0,6),1,-4,6,-4,1,rep(0,3)) Amat[,12] <- c(rep(0,7),1,-4,6,-4,1,rep(0,2)) Amat[,13] <- c(rep(0,8),1,-4,6,-4,1,0) Amat[,14] <- c(4,-2,rep(0,9),1,-2,1) Ainv <- solve(Amat) pfrac <- Ainv %*% gamma # Define spectra functions for seasonal and nonseasonal, to be minimized. # Lambda is a frequency between 0 and 1. seasFunc <- function(lambda,varP) { cosvec <- cbind(cos(pi*lambda),cos(pi*2*lambda),cos(pi*3*lambda), cos(pi*4*lambda),cos(pi*5*lambda),cos(pi*6*lambda), cos(pi*7*lambda),cos(pi*8*lambda),cos(pi*9*lambda), cos(pi*10*lambda)) numer <- varP[3] + 2*varP[4:13]%*%t(cosvec) denom <- abs(12 + 2*(12-seq(1:11))%*%t(cbind(cosvec,cos(pi*11*lambda)))) return(numer/denom) } trendFunc <- function(lambda,varP) { numer <- varP[1] + 2*varP[2]*cos(pi*lambda) denom <- 6 - 8*cos(pi*lambda) + 2*cos(pi*2*lambda) return(numer/denom) } # Compute minima of these functions lambVec <- seq(1,10000)/10000 tol <- 0 Smin <- min(seasFunc(lambVec,pfrac)) Smin <- Smin - tol Tmin <- min(trendFunc(lambVec,pfrac)) # Compute new spectra irrVar <- pfrac[14] + Smin + Tmin seasACF <- c(pfrac[3:13],0) -1*Smin*(13-seq(1:12)) trendACF <- c(pfrac[1:2],0) -1*Tmin*c(6,-4,1) saACF <- trendACF + c(6,-4,1)*irrVar # Compute spectral decompositions seasMA <- specFact(c(rev(seasACF),seasACF[-1])) trendMA <- specFact(c(rev(trendACF),trendACF[-1])) saMA <- specFact(c(rev(saACF),saACF[-1])) seasMA <- c(seasMA[-1]/seasMA[1],seasMA[1]^2) trendMA <- c(trendMA[-1]/trendMA[1],trendMA[1]^2) saMA <- c(saMA[-1]/saMA[1],saMA[1]^2) return(list(Re(trendMA),Re(seasMA),Re(irrVar),Re(saMA))) } air.out <- airlineDecomp(par.mle[[3]][[1]])
mdl2 <- NULL mdl2 <- sigex.add(mdl2,seq(1,N),"arma",c(0,2),NULL,"trend",c(1,-2,1)) mdl2 <- sigex.add(mdl2,seq(1,N),"arma",c(0,11),NULL,"seasonal",rep(1,12)) mdl2 <- sigex.add(mdl2,seq(1,N),"arma",c(0,0),NULL,"irregular",1) mdl2 <- sigex.meaninit(mdl2,data.ts,0) mdl2 <- sigex.reg(mdl2,1,ts(td.weights[,1,drop=FALSE],start=start.time, frequency=period,names="TD Monday")) mdl2 <- sigex.reg(mdl2,1,ts(td.weights[,2,drop=FALSE],start=start.time, frequency=period,names="TD Tuesday")) mdl2 <- sigex.reg(mdl2,1,ts(td.weights[,3,drop=FALSE],start=start.time, frequency=period,names="TD Wednesday")) mdl2 <- sigex.reg(mdl2,1,ts(td.weights[,4,drop=FALSE],start=start.time, frequency=period,names="TD Thursday")) mdl2 <- sigex.reg(mdl2,1,ts(td.weights[,5,drop=FALSE],start=start.time, frequency=period,names="TD Friday")) mdl2 <- sigex.reg(mdl2,1,ts(td.weights[,6,drop=FALSE],start=start.time, frequency=period,names="TD Saturday")) mdl2 <- sigex.reg(mdl2,1,ts(as.matrix(easter.regs),start=start.time, frequency=period,names="Easter"))
constraint <- NULL constraint <- rbind(constraint, sigex.constrainreg(mdl2,data.ts,list(seq(2,6)),NULL)) par.mle2 <- sigex.default(mdl2,data.ts,constraint) par.mle2[[2]][[1]] <- air.out[[1]][3]*exp(par.mle[[2]][[1]]) par.mle2[[2]][[2]] <- air.out[[2]][12]*exp(par.mle[[2]][[1]]) par.mle2[[2]][[3]] <- air.out[[3]][1]*exp(par.mle[[2]][[1]]) par.mle2[[3]][[1]] <- matrix(air.out[[1]][1:2],nrow=1,ncol=2) par.mle2[[3]][[2]] <- matrix(air.out[[2]][1:11],nrow=1,ncol=11) par.mle2[[4]] <- par.mle[[4]] psi.mle2 <- sigex.par2psi(par.mle2,mdl2)
signal.trend <- sigex.signal(data.ts,par.mle2,mdl2,1) signal.seas <- sigex.signal(data.ts,par.mle2,mdl2,2) signal.sa <- sigex.signal(data.ts,par.mle2,mdl2,c(1,3))
extract.trend <- sigex.extract(data.ts,signal.trend,mdl2,par.mle2) extract.seas <- sigex.extract(data.ts,signal.seas,mdl2,par.mle2) extract.sa <- sigex.extract(data.ts,signal.sa,mdl2,par.mle2)
reg.trend <- sigex.fixed(data.ts,mdl2,1,par.mle2,"Trend") reg.mon <- sigex.fixed(data.ts,mdl2,1,par.mle2,"TD Monday") reg.tue <- sigex.fixed(data.ts,mdl2,1,par.mle2,"TD Tuesday") reg.wed <- sigex.fixed(data.ts,mdl2,1,par.mle2,"TD Wednesday") reg.thu <- sigex.fixed(data.ts,mdl2,1,par.mle2,"TD Thursday") reg.fri <- sigex.fixed(data.ts,mdl2,1,par.mle2,"TD Friday") reg.sat <- sigex.fixed(data.ts,mdl2,1,par.mle2,"TD Saturday") reg.easter <- sigex.fixed(data.ts,mdl2,1,par.mle2,"Easter") reg.seas <- reg.mon + reg.tue + reg.wed + reg.thu + reg.fri + reg.sat + reg.easter
trendcol <- "tomato" seascol <- "seagreen" sacol <- "navyblue" fade <- 40 par(mfrow=c(2,1)) plot(data.ts[,1],xlab="Year",ylab="", ylim=c(min(data.ts[,1]),max(data.ts[,1])),lwd=1) sigex.graph(extract.sa,reg.trend,start.time,period,1,0,sacol,fade) plot(ts(rep(NA,T),start=start.time,frequency=12), xlab="Year",ylab="",ylim=c(-5,5),lwd=1) sigex.graph(extract.seas,reg.seas,start.time,period,1,0,seascol,fade)
## spectral diagnostics: sa sigex.specar(ts(extract.sa[[1]],frequency=period, names=colnames(data.ts)),FALSE,1,period)
grid <- 200 frf.sa <- sigex.getfrf(data.ts,par.mle2,mdl2,c(1,3),TRUE,grid)
len <- 50 target <- array(diag(N),c(N,N,1)) wk.sa <- sigex.wk(data.ts,par.mle2,mdl2,c(1,3),target,TRUE,grid,len)
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.