library(hrbrthemes); library(fpp3)
load(url("https://github.com/robertwwalker/Essex-Data/raw/main/LungDeaths.RData"))
<- mdeaths; Females <- fdeaths
Males <- cbind(Males, Females) %>% as_tsibble()
Lung.Deaths %>% autoplot() + theme_ipsum_rc() + labs(y="Lung Deaths", x="Month [1M]", title="Lung Deaths among Males and Females") + guides(color="none") Lung.Deaths
Slides
Dynamic Regression
Regression techniques can be reexamined through the lens of dynamic linear models and systems of linear equations. Whether autoregressive distributed lag models or VAR systems and structural time series, regression approaches to time series almost inevitably culminate in thinking about causation as conceived by Clive Granger – Granger causality.
Today we cover chapters 3 and 4 in TSASS spanning dynamic regression models and dynamic systems. We will start with dynamic regression models by detailing how they are specified and interpreted with distributed lag and autoregressive distributed lag [ADL] models. We also examine the crucial issue of consistency before turning to structural time series models for multiple equations and their counterparts – VARs.
VARs
We will start with some data on lung deaths from Australia.
library(forecast)
mdeaths
fdeaths
save(mdeaths, fdeaths, file = "./img/LungDeaths.RData")
use "https://github.com/robertwwalker/Essex-Data/raw/main/Lung-Deaths.dta"
<- cbind(mdeaths, fdeaths) %>%
lung_deaths as_tsibble(pivot_longer = FALSE)
<- cbind(mdeaths, fdeaths) %>%
lung_deaths as_tsibble(pivot_longer = FALSE)
<- lung_deaths %>%
fit model(VAR(vars(mdeaths, fdeaths) ~ AR(3)))
report(fit)
Series: mdeaths, fdeaths
Model: VAR(3) w/ mean
Coefficients for mdeaths:
lag(mdeaths,1) lag(fdeaths,1) lag(mdeaths,2) lag(fdeaths,2)
0.6675 0.8074 0.3677 -1.4540
s.e. 0.3550 0.8347 0.3525 0.8088
lag(mdeaths,3) lag(fdeaths,3) constant
0.2606 -1.1214 538.7817
s.e. 0.3424 0.8143 137.1047
Coefficients for fdeaths:
lag(mdeaths,1) lag(fdeaths,1) lag(mdeaths,2) lag(fdeaths,2)
0.2138 0.4563 0.0937 -0.3984
s.e. 0.1460 0.3434 0.1450 0.3328
lag(mdeaths,3) lag(fdeaths,3) constant
0.0250 -0.315 202.0027
s.e. 0.1409 0.335 56.4065
Residual covariance matrix:
mdeaths fdeaths
mdeaths 58985.95 22747.94
fdeaths 22747.94 9983.95
log likelihood = -812.35
AIC = 1660.69 AICc = 1674.37 BIC = 1700.9
var mdeaths fdeaths, lags(1 2 3)
<- lung_deaths %>%
fit2 model(VAR(vars(mdeaths, fdeaths) ~ AR(2)))
report(fit2)
Series: mdeaths, fdeaths
Model: VAR(2) w/ mean
Coefficients for mdeaths:
lag(mdeaths,1) lag(fdeaths,1) lag(mdeaths,2) lag(fdeaths,2) constant
0.9610 0.3340 0.1149 -1.3379 443.8492
s.e. 0.3409 0.8252 0.3410 0.7922 124.4608
Coefficients for fdeaths:
lag(mdeaths,1) lag(fdeaths,1) lag(mdeaths,2) lag(fdeaths,2) constant
0.3391 0.2617 -0.0601 -0.2691 145.0546
s.e. 0.1450 0.3510 0.1450 0.3369 52.9324
Residual covariance matrix:
mdeaths fdeaths
mdeaths 62599.51 24942.79
fdeaths 24942.79 11322.70
log likelihood = -833.17
AIC = 1694.35 AICc = 1701.98 BIC = 1725.83
var mdeaths fdeaths, lags(1 2)
Granger causation wants a non-tidy format. I will use the conventional VAR
syntax from vars
that wants the collection of endogenous variables as inputs by themselves in a matrix form. We can also specify exogenous variable for such systems with their data matrix in the argument exogen=...
.
library(bruceR)
bruceR (version 0.8.8)
BRoadly Useful Convenient and Efficient R functions
Packages also loaded:
√ dplyr √ emmeans √ ggplot2
√ tidyr √ effectsize √ ggtext
√ stringr √ performance √ cowplot
√ forcats √ lmerTest √ see
√ data.table
Main functions of `bruceR`:
cc() Describe() TTEST()
add() Freq() MANOVA()
.mean() Corr() EMMEANS()
set.wd() Alpha() PROCESS()
import() EFA() model_summary()
print_table() CFA() lavaan_summary()
https://psychbruce.github.io/bruceR/
<- vars::VAR(lung_deaths[,c("mdeaths","fdeaths")], p=3, type="const")
Varmf granger_causality(Varmf)
Granger Causality Test (Multivariate)
F test and Wald χ² test based on VAR(3) model:
────────────────────────────────────────────────────────────────
F df1 df2 p Chisq df p
────────────────────────────────────────────────────────────────
------------------
mdeaths <= fdeaths 1.93 3 62 .134 5.80 3 .122
mdeaths <= ALL 1.93 3 62 .134 5.80 3 .122
------------------
fdeaths <= mdeaths 1.20 3 62 .316 3.61 3 .307
fdeaths <= ALL 1.20 3 62 .316 3.61 3 .307
────────────────────────────────────────────────────────────────
vargranger
%>%
fit ::forecast(h=12) %>%
fabletoolsautoplot(lung_deaths)
Female
%>%
lung_deaths model(VAR(vars(mdeaths, fdeaths) ~ AR(3))) %>%
residuals() %>%
pivot_longer(., cols = c(mdeaths,fdeaths)) %>%
filter(name=="fdeaths") %>%
as_tsibble(index=index) %>%
gg_tsdisplay(plot_type = "partial") + labs(title="Female residuals")
Male
%>%
lung_deaths model(VAR(vars(mdeaths, fdeaths) ~ AR(3))) %>%
residuals() %>%
pivot_longer(., cols = c(mdeaths,fdeaths)) %>%
filter(name=="mdeaths") %>%
as_tsibble(index=index) %>%
gg_tsdisplay(plot_type = "partial") + labs(title="Male residuals")
Easy Impulse Response
What happens if I shock one of the series; how does it work through the system?
The idea behind an impulse-response is core to counterfactual analysis with time series. What does our future world look like and what predictions arise from it and the model we have deployed?
Whether VARs or dynamic linear models or ADL models, these are key to interpreting a model in the real world.
Males
irf set "M:\t1.irf"
irf create irf1, order( mdeaths fdeaths)
irf graph irf
<- cbind(Males,Females)
VARMF <- vars::VAR(VARMF, p=3, type="const")
mod1 plot(vars::irf(mod1, boot=TRUE, impulse="Males"))
Females
irf set "M:\tF.irf"
irf create Female, order( fdeaths mdeaths)
irf graph irf
plot(vars::irf(mod1, boot=TRUE, impulse="Females"))