We first clear the workspace using rm(list = ls())and
then include all packages we need. If a package is missing in your R
distribution (which is quite likely initially), just use
install.packages("package_name") with the respective
package name to install it on your system. If you execute the code in
the file install_packages.R, then all necessary packages
will be installed into your R distribution. If the variable
export_graphs is set to TRUE, then the graphs
will be exported as pdf-files. In addition, we define a set of colors
here to make graphs look more beautiful. Furthermore, we define some
axis breaks for graphs to look nicer.
rm(list = ls())
library(zoo)
library(xts)
library(dynlm)
library(reshape2)
library(base)
library(ggplot2)
library(grid)
library(scales)
library(stringr)
library(tidyverse)
library(fredr)
library(formattable)
# should graphs be exported to pdf
export_pdf <- FALSE
# define some colors
mygreen <- "#00BA38"
myblue <- "#619CFF"
myred <- "#F8766D"
# define plotting breaks
xbreaks <- c(seq(from = as.Date("1950-01-01"), to = as.Date("2020-01-01"),by = "10 years"))
Now we want download several data series from the FRED database at
once. To this end, we’ve written a function get_fred_data
that allows us to do this. This function is stored in a separate file
named chap06_func_get_fred_data.R.
The function get_fred_data receives as inputs two arrays
that need to have the same length as well as three scalar values. The
array series contains the ID of each series that should be
downloaded. You can find the ID on the respective series website, in the
case of GDP per capita this is this one.. The array
names contains the respective names under which the series
should be stored in our final data structure. Finally, we need to pass
the starting date (start_date), the ending date
(end_date), and the frequency (freq) to the
function. Note that the starting and end date as well as the frequency
need to be identical for all series that should be downloaded. Once we
call the function get_fred_data with these arguments, it is
going to return a data structure that contains all the data we’ve asked
for.
# Load function to get FRED data
source("chap06_func_get_fred_data.R")
# US recession dates
selection <- data.frame(series = "USRECQP", names = "RECESSION")
# nominal time series
selection <- rbind(selection, c("GDP", "GDP"))
selection <- rbind(selection, c("PCEC", "CONS"))
selection <- rbind(selection, c("PCDG", "CONS_D"))
selection <- rbind(selection, c("PCND", "CONS_N"))
selection <- rbind(selection, c("PCESV", "CONS_S"))
selection <- rbind(selection, c("GPDI", "INV"))
selection <- rbind(selection, c("PRFI", "INV_R"))
selection <- rbind(selection, c("PNFI", "INV_N"))
selection <- rbind(selection, c("CBI", "INV_I"))
selection <- rbind(selection, c("GCE", "GOV"))
selection <- rbind(selection, c("EXPGS", "EXP"))
selection <- rbind(selection, c("IMPGS", "IMP"))
# price deflators
selection <- rbind(selection, c("GDPDEF", "P_GDP"))
selection <- rbind(selection, c("DPCERD3Q086SBEA", "P_CONS"))
selection <- rbind(selection, c("DDURRD3Q086SBEA", "P_CONS_D"))
selection <- rbind(selection, c("DNDGRD3Q086SBEA", "P_CONS_N"))
selection <- rbind(selection, c("DSERRD3Q086SBEA", "P_CONS_S"))
selection <- rbind(selection, c("A006RD3Q086SBEA", "P_INV"))
selection <- rbind(selection, c("A011RD3Q086SBEA", "P_INV_R"))
selection <- rbind(selection, c("A008RD3Q086SBEA", "P_INV_N"))
selection <- rbind(selection, c("A371RD3Q086SBEA", "P_INV_I"))
selection <- rbind(selection, c("A822RD3Q086SBEA", "P_GOV"))
selection <- rbind(selection, c("A020RD3Q086SBEA", "P_EXP"))
selection <- rbind(selection, c("A021RD3Q086SBEA", "P_IMP"))
# additional series
selection <- rbind(selection, c("CE16OV", "EMPL"))
selection <- rbind(selection, c("UNRATE", "UNEMP"))
selection <- rbind(selection, c("AWHMAN", "HOURS"))
selection <- rbind(selection, c("PRS85006092", "LPROD"))
selection <- rbind(selection, c("PRS85006151", "REALCOMP"))
selection <- rbind(selection, c("TB3MS", "NOMRATE"))
# pull all data series from FRED
fred <- get_fred_data(selection$series, selection$names, "1948-01-01", "2023-12-31", "q")
## [1] "Loading series GDP"
## [1] "Loading series PCEC"
## [1] "Loading series PCDG"
## [1] "Loading series PCND"
## [1] "Loading series PCESV"
## [1] "Loading series GPDI"
## [1] "Loading series PRFI"
## [1] "Loading series PNFI"
## [1] "Loading series CBI"
## [1] "Loading series GCE"
## [1] "Loading series EXPGS"
## [1] "Loading series IMPGS"
## [1] "Loading series GDPDEF"
## [1] "Loading series DPCERD3Q086SBEA"
## [1] "Loading series DDURRD3Q086SBEA"
## [1] "Loading series DNDGRD3Q086SBEA"
## [1] "Loading series DSERRD3Q086SBEA"
## [1] "Loading series A006RD3Q086SBEA"
## [1] "Loading series A011RD3Q086SBEA"
## [1] "Loading series A008RD3Q086SBEA"
## [1] "Loading series A371RD3Q086SBEA"
## [1] "Loading series A822RD3Q086SBEA"
## [1] "Loading series A020RD3Q086SBEA"
## [1] "Loading series A021RD3Q086SBEA"
## [1] "Loading series CE16OV"
## [1] "Loading series UNRATE"
## [1] "Loading series AWHMAN"
## [1] "Loading series PRS85006092"
## [1] "Loading series PRS85006151"
## [1] "Loading series TB3MS"
The series for GDP and its components we’ve downloaded are
nominal series. Therefore we have to deflate them into real series
before we can use them. Deflators, however, are usually calculated
separately for each component of GDP. Therefore, the sum of the deflated
GDP components usually doesn’t add up exactly to deflated GDP anymore.
We therefore adjust each series proportionally in order to make them
consistent with aggregate real GDP. This involves calculating the ratio
between real GDP and the sum of its components in the variable
factor. We then multiply each individual series with this
factor to make our data consistent. The argument that inflated series
don’t usually add up well also holds for real total consumption and real
total investment. We therefore construct these aggregates by adding up
the different real components of consumption and investment,
respectively. Finally, we calculate calculate net exports in both
nominal and real terms.
# calculate real variables by deflating nominal ones
for(var in c("GDP", "CONS_D", "CONS_N", "CONS_S", "INV_R", "INV_N", "INV_I", "GOV", "EXP", "IMP")) {
fred[paste("R_", var, sep="")] = fred[var]/fred[paste("P_", var, sep="")]*100
}
# calculate adjusted real GDP (because of different deflators that don't finally add up correctly)
factor <- fred$R_GDP/(fred$R_CONS_D + fred$R_CONS_N + fred$R_CONS_S +fred$R_INV_R + fred$R_INV_N + fred$R_INV_I + fred$R_GOV + fred$R_EXP - fred$R_IMP)
# scale series
for(var in c("CONS_D", "CONS_N", "CONS_S", "INV_R", "INV_N", "INV_I", "GOV", "EXP", "IMP")) {
fred[paste("R_", var, sep="")] = fred[paste("R_", var, sep="")]*factor
}
# calculate aggregate real consumption and investment
fred["R_CONS"] = fred["R_CONS_D"] + fred["R_CONS_N"] + fred["R_CONS_S"]
fred["R_INV"] = fred["R_INV_R"] + fred["R_INV_N"] + fred["R_INV_I"]
# determine net exports
fred$XM <- fred$EXP - fred$IMP
fred$R_XM <- fred$R_EXP - fred$R_IMP
The next step is to determine how recessions are different compared
to normal times. We start with calculating normal GDP growth in
y_normal, which is just the average growth rate of GDP over
the entire time horizon of our data. We can do this using the
diff function, which just calculates the forward difference
for a series, i.e. \(Y_{t+1} - Y_t\).
We then just have to take the mean of all the calculated GDP growth
rates. Next, we only select data from recessions into the variable
y_rec to calculate GDP growth rates again, but only in
recession times. After this exercise, y_normal contains the
normal GDP growth rate and y_rec the GDP growth rates in
recessions only.
# calculate regression beginnings and ends
fred$REC_DATES <- 0
fred$REC_DATES[2:length(fred$REC_DATES)] <- diff(fred$RECESSION)
# calculate normal GDP growth (in quarterly terms)
y_normal <- mean(diff(fred$R_GDP)/fred$R_GDP[1:length(fred$R_GDP)-1])
# GDP growth in recessions relative to normal growth
y_rec <- vector();
for(t in 1:length(fred$R_GDP)) {
if(fred$RECESSION[t] == 1 & fred$REC_DATES[t] != -1) {
y_rec <- append(y_rec, (fred$R_GDP[t+1] - fred$R_GDP[t])/fred$R_GDP[t])
}
}
# calculate mean across recessions
y_rec <- mean(y_rec)
Next, we calculate the share of each component in GDP as well
as its contribution to GDP growth in recessions relative to normal
times. The share of each component in total GDP is stored in
dat[i, 1]. To calculate the contribution of each variable
to GDP growth in recessions relative to normal times is a bit more
difficult. We first calculate the first difference of each component of
GDP (for aggregate consumption this for example is \(C_{t+1} - C_t\)) and relate it to the
respective value of GDP \(Y_t\). We do
this both for the entire time series of data (v_normal) as
well as for the recession dates only (v_rec). We finally
relate the difference in v_rec and v_normal to
the difference in y_rec and y_normal to get to
each component’s contribution in GDP growth.
# here statistics are stored
dat <- array(dim=c(10,2))
# iterate over relevant variables
i <- 1
for(var in c("CONS", "CONS_D", "CONS_N", "CONS_S", "INV", "INV_R", "INV_N", "INV_I", "GOV", "XM")) {
# get mean share in GDP
dat[i, 1] <- mean(unlist(fred[var]/fred["GDP"]))
# get real variable name
rvar <- paste("R_", var, sep="")
# calculate normal share in GDP growth of variable
v_normal <- mean(diff(unlist(fred[rvar]))/unlist(fred[1:length(fred$R_GDP)-1,]["R_GDP"]))
# variable share of GDP growth in recessions
v_rec <- vector();
for(t in 1:length(fred$R_GDP)) {
if(fred$RECESSION[t] == 1 & fred$REC_DATES[t] != -1) {
v_rec <- append(v_rec, unlist(fred[t+1,][rvar] - fred[t,][rvar])/fred$R_GDP[t])
}
}
# calculate mean across recessions
v_rec <- mean(v_rec)
# calculate share in GDP fall relative to normal growth
dat[i, 2] <- (v_rec - v_normal)/(y_rec - y_normal)
# increment i
i = i + 1
}
From the data we calculated above, we then create a simple table
using the formattable statement.
table_data <- data.frame("Component" =
c("Consumption", " - Durables", " - Nondurables", " - Services",
"Investment", " - Residential", " - Fixed Nonresidential", " - Inventories",
"Government Purchases", "Net Exports"))
table_data <- cbind(table_data, "Average share in GDP" = percent(dat[, 1]))
table_data <- cbind(table_data, "Average share in fall in GDP in recessions relative to normal growth" = percent(dat[, 2]))
# output table
formattable(table_data,
align= c("l", "c", "c"))
| Component | Average share in GDP | Average share in fall in GDP in recessions relative to normal growth |
|---|---|---|
| Consumption | 63.57% | 45.54% |
|
8.39% | 6.31% |
|
18.89% | 10.98% |
|
36.30% | 28.25% |
| Investment | 17.39% | 52.59% |
|
4.61% | 10.76% |
|
12.25% | 19.73% |
|
0.53% | 22.09% |
| Government Purchases | 20.46% | 7.87% |
| Net Exports | -1.42% | -6.00% |
Next, we determine the recession start and end dates. This is simply done to be able to shade recessions in the following graphs.
# date at beginning and end of recessions
rstart <- fred$date[fred$REC_DATES == 1]
rend <- fred$date[fred$REC_DATES == -1]
rec_df <- data.frame(rstart, rend)
Now we want to plot a couple of important series and study their
properties during recessions. With start out with percentage changes in
aggregate employment. The growth rates of employment can again be
calculated using the diff function.
# calculate employment changes
fred$D_EMPL <- NA
fred$D_EMPL[1:(length(fred$EMPL)-1)] <- diff(fred$EMPL)/fred$EMPL[1:(length(fred$EMPL)-1)]*100
# set minimum and maximum
ymin <- -14
ymax <- 8
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_hline(yintercept=0, color="gray", linewidth=0.5) +
geom_line(aes(x=date, y=D_EMPL), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 2), expand=c(0, 0)) +
labs(x = "Year t",
y = "Employment Change (in %)") +
theme_bw()
# print the plot
print(myplot)
Next, we take a look at unemployment rates.
# set minimum and maximum
ymin <- 0
ymax <- 15
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_line(aes(x=date, y=UNEMP), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 2.5), expand=c(0, 0)) +
labs(x = "Year t",
y = "Unemployment Rate (quarterly, in %)") +
theme_bw()
# print the plot
print(myplot)
This series plots average weekly hours of production workers in manufacturing.
# set minimum and maximum
ymin <- 36
ymax <- 44
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_line(aes(x=date, y=HOURS), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 2), expand=c(0, 0)) +
labs(x = "Year t",
y = "Average Weekly Hours, Prod. Workers") +
theme_bw()
# print the plot
print(myplot)
This series contains changes in output per hour in non-farm businesses.
# set minimum and maximum
ymin <- -8
ymax <- 18
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_hline(yintercept=0, color="gray", linewidth=0.5) +
geom_line(aes(x=date, y=LPROD), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 4), expand=c(0, 0)) +
labs(x = "Year t",
y = "Change in Output per Hour (in %)") +
theme_bw()
# print the plot
print(myplot)
Again for non-farm businesses, but this time changes in real compensation per hour.
# set minimum and maximum
ymin <- -4
ymax <- 10
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_hline(yintercept=0, color="gray", linewidth=0.5) +
geom_line(aes(x=date, y=REALCOMP), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 4), expand=c(0, 0)) +
labs(x = "Year t",
y = "Change in Real Compensation per Hour (in %)") +
theme_bw()
# print the plot
print(myplot)
Finally, we take a look at prices and interest rates. This is the inflation rate.
# calculate annualized inflation from GDP deflator
fred$INFL <- NA
fred$INFL[5:(length(fred$P_GDP))] <- diff(fred$P_GDP, lag = 4)/fred$P_GDP[1:(length(fred$P_GDP)-4)]*100
# set minimum and maximum
ymin <- -2
ymax <- 12
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_hline(yintercept=0, color="gray", linewidth=0.5) +
geom_line(aes(x=date, y=INFL), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 2), expand=c(0, 0)) +
labs(x = "Year t",
y = "Inflation Relative to Previous Year (in %)") +
theme_bw()
# print the plot
print(myplot)
An this is the nominal interest rate on 3-month treasuries.
# set minimum and maximum
ymin <- 0
ymax <- 16
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_line(aes(x=date, y=NOMRATE), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 2), expand=c(0, 0)) +
labs(x = "Year t",
y = "Nominal Interest on 3-month Treasuries (in %)") +
theme_bw()
# print the plot
print(myplot)
The difference between the nominal rate and inflation leads us to the ex-post real rate.
# set minimum and maximum
ymin <- -8
ymax <- 8
dy <- (abs(ymin)+abs(ymax))/2
# create plot
myplot <- ggplot(data = fred) +
geom_rect(data=rec_df, aes(xmin=rstart, xmax=rend, ymin=ymin-0.05*dy, ymax=ymax+0.05*dy), fill='gray', alpha=0.5) +
geom_hline(yintercept=0, color="gray", linewidth=0.5) +
geom_line(aes(x=date, y=NOMRATE-INFL), color="darkblue", linewidth=0.5) +
scale_x_date(breaks = xbreaks, date_labels = "%Y", expand=c(0, 0)) +
scale_y_continuous(breaks=seq(ymin, ymax, 2), expand=c(0, 0)) +
labs(x = "Year t",
y = "Real Interest on 3-month Treasuries (in %)") +
theme_bw()
# print the plot
print(myplot)