Chapter 20: Multivariate Time Series Methods
Load required packages
library(bvartools)
library(dplyr)
library(ggplot2)
library(spam)
library(tidyr)
Data
US macro data until 2007Q4
# Specify URL
url <- "https://web.ics.purdue.edu/~jltobias/second_edition/Chapter20/code_for_exercise_1/US_macrodata.csv"
# Load data
us_macro_2007 <- read.csv(url, col.names = c("date", "Dp", "u", "r"))
# Omit NA values
us_macro_2007 <- na.omit(us_macro_2007)
# Transform into time-series object
us_macro_2007 <- ts(us_macro_2007[, -1], start = c(1959, 2), frequency = 4)
Exercise 20.1
Prepare the data
temp <- gen_var(us_macro_2007, p = 2, deterministic = "const")
y <- temp$Y
x <- temp$Z
k <- NROW(y)
tt <- ncol(y)
z <- kronecker(t(x), diag(1, k))
m <- ncol(z)
Specify the priors
mu_prior <- matrix(0, m) # Prior mean
v_i_prior <- diag(1, m) # Prior variance
diag(v_i_prior)[m - k + 1:k] <- 1 / 10 # Deterministics
df_prior <- k + 3
df_post <- tt + df_prior
scale_prior = diag(1, k)
Initial values
ols <- tcrossprod(y, x) %*% solve(tcrossprod(x))
epsilon <- y - ols %*% x
sigma <- tcrossprod(epsilon) / tt
sigma_i <- solve(sigma)
Gibbs sampler
iterations <- 21000 # Iterations
burnin <- 1000 # Burnin
# Storage for coefficients
store <- iterations - burnin
draws_b <- matrix(NA, m, store)
draws_sigma <- matrix(NA, k * k, store)
# Start Gibbs sampler
for (draw in 1:iterations) {
# Draw parameters
b <- post_normal_sur(y = y, z = z, sigma_i = sigma_i,
a_prior = mu_prior, v_i_prior = v_i_prior)
# Error
epsilon <- y - matrix(b, k) %*% x
scale_post <- scale_prior + tcrossprod(epsilon)
sigma_i <- matrix(rWishart(1, df_post, solve(scale_post))[,,1], k)
sigma <- solve(sigma_i)
# Save post-burnin draws
if (draw > burnin) {
draws_b[, draw - burnin] <- b
draws_sigma[, draw - burnin] <- sigma
}
}
Create a bvar
object for IRF
draws_a <- draws_b[1:(m - k), ] # Draws of non-deterministic coefficients
draws_det <- draws_b[m - k + 1:k, ] # Draws of deterministic coefficients
ex_20_1 <- bvar(y = y, x = x, A = draws_a, C = draws_det, Sigma = draws_sigma)
ex_20_1 <- thin(ex_20_1) # Thin the output
Impuse response functions
Dp <- irf(ex_20_1, impulse = "r", response = "Dp", n.ahead = 20, type = "oir", keep_draws = TRUE)
u <- irf(ex_20_1, impulse = "r", response = "u", n.ahead = 20, type = "oir", keep_draws = TRUE)
r <- irf(ex_20_1, impulse = "r", response = "r", n.ahead = 20, type = "oir", keep_draws = TRUE)
Dp <- colMeans(Dp)
u <- colMeans(u)
r <- colMeans(r)
temp <- cbind(Dp, u, r) %>%
as.data.frame() %>%
mutate(time = 1:n() - 1) %>%
pivot_longer(cols = c("Dp", "u", "r")) %>%
mutate(name = factor(name, levels = c("Dp", "u", "r"),
labels = c("Inflation", "Unemployment", "Interest rate")))
ggplot(temp, aes(x = time, y = value)) +
geom_line() +
facet_wrap(~ name, scales = "free")
Exercise 20.6: Time varying parameter VAR
Data: US macro data until 2007Q4
# Specify URL
url <- "https://web.ics.purdue.edu/~jltobias/second_edition/Chapter20/code_for_exercise_5/US_macrodata.csv"
# Load data
us_macro_2007 <- read.csv(url, col.names = c("date", "Dp", "u", "r"))
# Omit NA values
us_macro_2007 <- na.omit(us_macro_2007)
# Transform into time-series object
us_macro_2007 <- ts(us_macro_2007[, -1], start = c(1959, 2), frequency = 4)
# Genenerate data matrices
temp <- gen_var(us_macro_2007, p = 2, deterministic = "const")
y <- temp$Y
x <- temp$Z
k <- nrow(y) # Number of endogenous variables
tt <- ncol(y) # Number of obs
m <- nrow(x) # Number of regressors
n <- m * k # Number of estimated coefficients
Estimation
Priors
# Initial conditions
a0_mu_prior <- matrix(0, n)
b0_v_i_prior <- diag(1, n)
diag(b0_v_i_prior)[n - k + 1:k] <- 1 / 10 # Prior for determinsitic terms
# Priors for measurement equation errors
sigma_df_prior <- k + 3
sigma_df_post <- tt + sigma_df_prior
sigma_scale_prior <- diag(1, k)
# Priors for state equation errors
q_shape_prior <- 3
q_shape_post <- q_shape_prior + tt / 2
q_rate_prior <- rep(.01^2, n)
q_rate_prior[n - k + 1:k] <- .1^2 # Determinsitic
Initial values
y_vec <- matrix(y)
z <- matrix(0, k * tt, n * tt)
for (i in 1:tt) {
z[(i - 1) * k + 1:k, (i - 1) * n + 1:n] <- kronecker(t(x[, i]), diag(1, k))
}
z <- as.spam(z)
beta0 <- tcrossprod(y, x) %*% solve(tcrossprod(x))
sigma_temp <- tcrossprod(y - beta0 %*% x) / tt
sigma_i_temp <- solve(sigma_temp)
sigma_i <- kronecker(diag(1, tt), sigma_i_temp)
sigma_i <- as.spam(sigma_i)
beta0 <- matrix(beta0)
q_i <- kronecker(diag(1, tt), diag(100, n))
q_i <- as.spam(q_i)
h <- diag(1, m * k * tt)
diag(h[-(1:(m * k)), 1:(m * k * (tt - 1))]) <- -1
h <- as.spam(h)
Gibbs sampler
iterations <- 21000
burnin <- 1000
# Data containers for draws
draws_beta <- NULL
for (i in 1:tt) {
draws_beta[[i]] <- matrix(NA, n, iterations - burnin)
}
draws_sigma <- matrix(NA, k * k, iterations - burnin)
# Start Gibbs sampler
for (draw in 1:iterations) {
# Draw parameters
HQiH <- crossprod(h, q_i) %*% h
XSi <- crossprod(z, sigma_i)
K_beta <- HQiH + XSi %*% z
mu_beta <- matrix(solve(K_beta, HQiH %*% kronecker(matrix(1, tt), beta0) + XSi %*% y_vec))
beta <- mu_beta + solve.spam(chol(K_beta), rnorm(n * tt))
# Measurement eq. variance-covariance matrix
u <- matrix(y_vec - z %*% beta, k)
sigma_i_temp <- rWishart(n, sigma_df_post, solve(sigma_scale_prior + tcrossprod(u)))[,, 1]
sigma_i <- as.spam(kronecker(diag(1, tt), sigma_i_temp))
# State eq. error variances
beta <- matrix(beta, n)
v <- apply(beta - cbind(beta0, beta[, -tt]), 1, function(x) {sum(x^2)})
q_post <- cbind(q_shape_post, q_rate_prior + v / 2)
q_i_temp <- apply(q_post, 1, function(x) {rgamma(1, shape = x[1], rate = x[2])})
diag(q_i) <- rep(q_i_temp, tt)
# Initial condition
K_beta0 <- b0_v_i_prior + q_i[1:n, 1:n]
mu_beta0 <- solve(K_beta0, b0_v_i_prior %*% a0_mu_prior + q_i[1:n, 1:n] %*% beta[, 1])
beta0 <- mu_beta0 + solve(chol(K_beta0), rnorm(n))
# Save draws
if (draw > burnin) {
pos_draw <- draw - burnin
for (i in 1:tt) {
draws_beta[[i]][, pos_draw] <- as.matrix(beta[, i])
}
draws_sigma[, pos_draw] <- solve(sigma_i_temp)
}
}
Impulse responses
Create bvar
obejcts for further analysis
# For 1975Q1
tt_1975 <- which(time(us_macro_2007) == 1975) - 2
bvar_1975 <- bvar(y = y, x = x,
A = draws_beta[[tt_1975]][1:(n - k),],
C = draws_beta[[tt_1975]][n - k + 1:k, ],
Sigma = draws_sigma)
# For 2005Q1
tt_2005 <- which(time(us_macro_2007) == 2005) - 2
bvar_2005 <- bvar(y = y, x = x,
A = draws_beta[[tt_2005]][1:(n - k),],
C = draws_beta[[tt_2005]][n - k + 1:k, ],
Sigma = draws_sigma)
Obtain impulse responses for inflation
irf_1975 <- irf(bvar_1975, impulse = "r", response = "Dp",
n.ahead = 20, type = "oir", keep_draws = TRUE)
irf_2005 <- irf(bvar_2005, impulse = "r", response = "Dp",
n.ahead = 20, type = "oir", keep_draws = TRUE)
# Difference between the IRF
diff_irf_Dp <- irf_2005 - irf_1975
diff_irf_Dp <- t(apply(diff_irf_Dp, 2, quantile, probs = c(.05, .5, .95)))
diff_irf_Dp <- diff_irf_Dp %>%
as.data.frame() %>%
mutate(var = "Inflation",
time = 1:n() - 1)
# Mean IRF
irf_1975 <- colMeans(irf_1975)
irf_2005 <- colMeans(irf_2005)
irf_Dp <- cbind(irf_1975, irf_2005) %>%
as.data.frame() %>%
mutate(var = "Inflation",
time = 1:n() - 1)
Obtain impulse responses for unemployment
irf_1975 <- irf(bvar_1975, impulse = "r", response = "u",
n.ahead = 20, type = "feir", keep_draws = TRUE)
irf_2005 <- irf(bvar_2005, impulse = "r", response = "u",
n.ahead = 20, type = "feir", keep_draws = TRUE)
# Difference between the IRF
diff_irf_u <- irf_2005 - irf_1975
diff_irf_u <- t(apply(diff_irf_u, 2, quantile, probs = c(.05, .5, .95)))
diff_irf_u <- diff_irf_u %>%
as.data.frame() %>%
mutate(var = "Unemployment",
time = 1:n() - 1)
# Mean IRF
irf_1975 <- colMeans(irf_1975)
irf_2005 <- colMeans(irf_2005)
irf_u <- cbind(irf_1975, irf_2005) %>%
as.data.frame() %>%
mutate(var = "Unemployment",
time = 1:n() - 1)
Obtain impulse responses for interest rate
irf_1975 <- irf(bvar_1975, impulse = "r", response = "r",
n.ahead = 20, type = "feir", keep_draws = TRUE)
irf_2005 <- irf(bvar_2005, impulse = "r", response = "r",
n.ahead = 20, type = "feir", keep_draws = TRUE)
# Difference between the IRF
diff_irf_r <- irf_2005 - irf_1975
diff_irf_r <- t(apply(diff_irf_r, 2, quantile, probs = c(.05, .5, .95)))
diff_irf_r <- diff_irf_r %>%
as.data.frame() %>%
mutate(var = "Interest rate",
time = 1:n() - 1)
# Mean IRF
irf_1975 <- colMeans(irf_1975)
irf_2005 <- colMeans(irf_2005)
irf_r <- cbind(irf_1975, irf_2005) %>%
as.data.frame() %>%
mutate(var = "Interest rate",
time = 1:n() - 1)
Figure 20.2: Mean IRF
temp <- bind_rows(irf_Dp, irf_u, irf_r) %>%
# Bring it into long form
pivot_longer(cols = starts_with("irf_"),
names_to = "Period") %>%
# For better labelling in the plot
mutate(var = factor(var, levels = c("Inflation", "Unemployment", "Interest rate")),
Period = factor(Period, levels = c("irf_1975", "irf_2005"),
labels = c("1975", "2005")))
# Plot
ggplot(temp, aes(x = time, y = value, colour = Period)) +
facet_wrap(~ var, scales = "free") +
geom_line() +
theme(legend.position = "bottom", legend.title = element_blank())
Figure 20.3: Plot differences between IRF
temp <- bind_rows(diff_irf_Dp, diff_irf_u, diff_irf_r)
names(temp) <- c("ymin", "y", "ymax", "var", "time")
temp <- temp %>%
mutate(var = factor(var, levels = c("Inflation", "Unemployment", "Interest rate")))
# Plot
ggplot(temp, aes(x = time)) +
geom_ribbon(aes(ymin = ymin, ymax = ymax, fill = "a"), alpha = .3, show.legend = FALSE) +
geom_line(aes(y = y, colour = "a"), show.legend = FALSE) +
facet_wrap(~ var, scales = "free")
Work in progress