Chapter 18: State Space and Unobserved Components Models

Exercise 18.1: The local level model

Data: US PCE inflation until 2015Q4

# Specify URL
url <- "https://web.ics.purdue.edu/~jltobias/second_edition/Chapter18/code_for_exercise_1/USPCE_2015Q4.csv"

# Load data
pce <- read.csv(url, header = FALSE, col.names = "pci")

# Log growth rates
pce <- diff(ts(log(pce), start = 1959, frequency = 4))

# Rescale
y <- matrix(pce * 100 * 4, 1)
tt <- ncol(y) # T
z <- diag(1, tt) # Data matrix

Estimation

Prior

a0 <- 5
b0 <- 100

Initial values

library(bvartools)
library(Matrix)

# Difference matrix
H <- diag(1, tt)
diag(H[2:tt, 1:(tt - 1)]) <- -1

# (Inverse) variance of the measeurement equation
sigma <- var(c(y))
sigma_i <- solve(sigma)
sigma_i <- kronecker(diag(1, tt), sigma_i)

# Inverse variance of the transition equation
q_i <- kronecker(diag(1, tt), 1 / 100)

# Inital state
tau0 <- matrix(y[1])

# Transform into sparse matrices so that function chan_jeliazkov can be used
z <- Matrix(z)
H <- Matrix(H)
sigma_i <- Matrix(sigma_i)
q_i <- Matrix(q_i)

Gibbs sampler

iterations <- 21000
burnin <- 1000

# Container for draws
draws_tau <- matrix(NA, tt, iterations - burnin)

for (draw in 1:iterations) {
  # Draw trend
  a <- chan_jeliazkov(y, z, sigma_i, H, q_i, tau0)
  
  # Draw measurement eq. variance
  u <- y - a[, -1]
  diag(sigma_i) <- rgamma(1, shape = 3 + tt / 2, rate = 2 + tcrossprod(u) / 2)
  
  # Draw transition eq. variance
  w <- a[, -1] - matrix(a0, 1, tt)
  w <- w %*% as.matrix(crossprod(H)) %*% t(w)
  diag(q_i) <- rgamma(1, shape = 3 + tt / 2, rate = 2 * .25^2 + w / 2)
  
  # Draw initial condition
  K_tau0 <- 1 / b0 + q_i[1, 1]
  mu_tau0 <- 1 / K_tau0 * (a0 / b0 + a[, 2] * q_i[1, 1])
  tau0 <- rnorm(1, mu_tau0, sqrt(1 / K_tau0))
  
  # Save draws
  if (draw > burnin) {
    draws_tau[, draw - burnin] <- a[, -1]
  }
}

Plot estimated prior mean of tau

tau <- apply(draws_tau, 1, mean) # Mean
tau <- cbind(c(y), tau) # Combine with original series
tau <- ts(tau, start = 1959, frequency = 4)

plot(tau, plot.type = "single", col = c("black", "red"),
     ylim = c(-15, 20), ylab = "")

Exercise 18.2: Estimating the output gap

The approach follows Grant, A. L., & Chan, J. C. C. (2017). Reconciling output gaps: Unobserved components model and Hodrick-Prescott filter, Journal of Economic Dynamics and Control, 75, 114-121.

Data: US log GDP until 2015Q4

# Specify URL
url <- "https://web.ics.purdue.edu/~jltobias/second_edition/Chapter18/code_for_exercise_2/USGDP_2015Q4.csv"

# Download data
gdp <- read.csv(url, header = FALSE)[, 1]

y <- matrix(log(gdp) * 100) # Log GDP
p <- 2 # Lag of cyclical component
tt <- nrow(y) # T

Estimation

Priors

# Priors of phi
prior_phi_mu <- matrix(c(1.3, -.7))
prior_phi_v_i <- diag(1, p)

# Priors of gamma
prior_gamma_mu <- matrix(c(750, 750)) # Should be close to first value of the series
prior_gamma_v_i <- diag(1 / 100, p)

# Priors for sigma2_tau
prior_s_tau <- .01

# Priors for sigma2_c
prior_s_c_shape <- 3
prior_s_c_rate <- 2

Initial values

# X_gamma
x_gamma <- cbind(2:(tt + 1), -1:-tt)

# H_2
h2 <- diag(1, tt)
diag(h2[-1, -tt]) <- -2
diag(h2[-(1:2), -((tt - 1):tt)]) <- 1
h2h2 <- crossprod(h2)

# H_phi
h_phi <- diag(1, tt)
phi <- matrix(c(1.34, -.7))
for (i in 1:p) {
  diag(h_phi[-(1:i), -((tt - i):tt)]) <- -phi[i,]
}

# Inverse of sigma tau
s_tau_i <- 1 / .001

# Inverse of sigma c
s_c_i <- 1 / .5

# gamma
gamma <- t(rep(y[1], 2)) # Should be close to first value of the series

Gibbs sampler

iterations <- 11000
burnin <- 1000

# Data containers for draws
draws_tau <- matrix(NA, tt, iterations - burnin)
draws_c <- matrix(NA, tt, iterations - burnin)

# Start Gibbs sampler
for (draw in 1:iterations) {
  # Draw tau
  alpha <- solve(h2, matrix(c(2 * gamma[1] - gamma[2], -gamma[1], rep(0, tt - 2))))
  sh2 <- s_tau_i * h2h2
  shphi <- s_c_i * as.matrix(crossprod(h_phi))
  K_tau <- sh2 + shphi
  mu_tau <- solve(K_tau, sh2 %*% alpha + shphi %*% y)
  tau <- mu_tau + solve(chol(K_tau), rnorm(tt))
  
  # Draw phi
  c <- c(rep(0, p), y - tau)
  temp <- embed(c, 1 + p)
  c <- matrix(temp[, 1])
  x_phi <- temp[, -1]
  K_phi <- prior_phi_v_i  + s_c_i * crossprod(x_phi)
  mu_phi <- solve(K_phi, prior_phi_v_i %*% prior_phi_mu + s_c_i * crossprod(x_phi, c))
  phi_can <- mu_phi + solve(chol(K_phi), rnorm(p))
  if (sum(phi_can) < .99 & phi_can[2] - phi_can[1] < .99 & phi_can[2] > -.99) {
    phi <- phi_can
    for (i in 1:p) {
      diag(h_phi[-(1:i), -((tt - i):tt)]) <- -phi[i,]
    }
  }
  
  # Draw variance c
  s_c_i <- rgamma(1, shape = 3 + tt / 2, rate = 2 + crossprod(c - x_phi %*% phi) / 2)
  
  # Draw variance tau
  tausq_sum <- sum(diff(diff(c(gamma[2:1], tau)))^2)
  s_tau_can <- seq(from = runif(1) / 1000,
                   to = prior_s_tau - runif(1) / 1000, length.out = 500)
  lik <- -tt / 2 * log(s_tau_can) - tausq_sum / (2 * s_tau_can)
  plik <- exp(lik - max(lik))
  plik <- plik / sum(plik)
  plik <- cumsum(plik)
  s_tau_i <- 1 / s_tau_can[runif(1) < plik][1]
  
  # Draw gamma
  sxh2 <- s_tau_i * crossprod(x_gamma, h2h2)
  K_gamma <- as.matrix(prior_gamma_v_i + sxh2 %*% x_gamma)
  mu_gamma <- solve(K_gamma, prior_gamma_v_i %*% prior_gamma_mu + sxh2 %*% tau)
  gamma <- mu_gamma + solve(chol(K_gamma), rnorm(2))
  
  # Save draws
  if (draw > burnin) {
    pos_draw <- draw - burnin
    draws_tau[, pos_draw] <- tau
    draws_c[, pos_draw] <- c
  }
}

Plot cyclical component

mean_c <- cbind(0, apply(draws_c, 1, mean))
mean_c <- ts(mean_c, start = 1949, frequency = 4)
plot(mean_c, plot.type = "single", ylab = "", ylim = c(-8, 6))

Plot annualised trend growth

temp <- apply(draws_tau, 2, diff) * 4
mean_dtau <- ts(apply(temp, 1, mean), start = 1949, frequency = 4)
plot(mean_dtau, plot.type = "single", ylim = c(1, 4.5), ylab = "")

Work in progress