Nothing
## ----include = FALSE----------------------------------------------------------
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.width = 7,
fig.height = 4.5,
out.width = "100%"
)
## ----setup, message=FALSE-----------------------------------------------------
library(MacroFilters)
library(ggplot2)
data("fr_gdp", package = "MacroFilters")
data("es_gdp", package = "MacroFilters")
## ----input-agnosticism--------------------------------------------------------
set.seed(7)
y_raw <- cumsum(rnorm(60)) + (1:60) * 0.3 # a simple integrated series
# As plain numeric
hp_num <- hp_filter(y_raw)
class(hp_num$trend) # numeric
# As a monthly ts object
y_ts <- ts(y_raw, start = c(2019, 1), frequency = 12)
hp_ts <- hp_filter(y_ts)
class(hp_ts$trend) # ts — output matches input
## ----hp-filter----------------------------------------------------------------
set.seed(42)
n <- 100
y <- ts(100 + 0.4 * (1:n) + 5 * sin(2 * pi * (1:n) / 20) + rnorm(n, sd = 2),
start = c(2000, 1), frequency = 4)
hp <- hp_filter(y)
hp
## ----hp-plot, echo=FALSE, fig.height=3----------------------------------------
df_hp <- data.frame(
t = as.numeric(time(y)),
data = as.numeric(y),
trend = as.numeric(hp$trend),
cycle = as.numeric(hp$cycle)
)
ggplot(df_hp, aes(x = t)) +
geom_line(aes(y = data, colour = "Observed"), linewidth = 0.6, linetype = "dashed") +
geom_line(aes(y = trend, colour = "Trend"), linewidth = 1.1) +
scale_colour_manual(values = c("Observed" = "grey60", "Trend" = "#0072B2")) +
labs(title = "HP Filter", subtitle = paste0("\u03bb = ", hp$meta$lambda),
x = "Year", y = "Value", colour = NULL) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
## ----hp-cycle-plot, echo=FALSE, fig.height=2.8--------------------------------
ggplot(df_hp, aes(x = t, y = cycle)) +
geom_hline(yintercept = 0, linetype = "dashed", colour = "grey40") +
geom_line(colour = "#0072B2", linewidth = 0.8) +
labs(title = "HP Cycle", x = "Year", y = "Cycle") +
theme_minimal(base_size = 12)
## ----hamilton-filter----------------------------------------------------------
ham <- hamilton_filter(y) # auto-detects h = 8 for quarterly
ham
## ----bhp-filter---------------------------------------------------------------
bhp <- bhp_filter(y, stopping = "bic")
bhp
## ----fred-download, eval=FALSE------------------------------------------------
# # FRED public endpoint — no API key needed.
# # See data-raw/intl_gdp.R for the full reproducible download script.
# read_fred <- function(id) {
# url <- sprintf("https://fred.stlouisfed.org/graph/fredgraph.csv?id=%s", id)
# dt <- read.csv(url, col.names = c("date", "gdp_real"), na.strings = ".")
# dt$date <- as.Date(dt$date)
# dt$gdp_log <- log(as.numeric(dt$gdp_real))
# dt[!is.na(dt$gdp_real), ]
# }
# fr_raw <- read_fred("CLVMNACSCAB1GQFR")
# es_raw <- read_fred("CLVMNACSCAB1GQES")
## ----mbh-demo-----------------------------------------------------------------
# Apply HP + MBH per country.
# For log-level series, auto d (MAD of diff) is too tight — calibrate d on the
# cycle scale instead (see vignette "Hyperparameter Tuning for the MBH Filter").
make_trend_df <- function(raw, country) {
dt <- raw[raw$date >= as.Date("2000-01-01"), ]
g <- ts(dt$gdp_log, start = c(2000, 1), frequency = 4)
hp <- hp_filter(g)
mbh <- mbh_filter(g, d = mad(hp$cycle))
data.frame(country = country,
t = as.numeric(time(g)),
observed = as.numeric(g),
hp = as.numeric(hp$trend),
mbh = as.numeric(mbh$trend))
}
df_plot <- rbind(
make_trend_df(fr_gdp, "France"),
make_trend_df(es_gdp, "Spain")
)
# Keep Spain filter objects for the S3 class examples in Section 5
dt_es <- es_gdp[es_gdp$date >= as.Date("2000-01-01"), ]
gdp <- ts(dt_es$gdp_log, start = c(2000, 1), frequency = 4)
hp_res <- hp_filter(gdp)
mbh_res <- mbh_filter(gdp, d = mad(hp_res$cycle))
mbh_res
## ----mbh-plot, echo=FALSE-----------------------------------------------------
ggplot(df_plot, aes(x = t)) +
geom_line(aes(y = observed, colour = "Observed"), linewidth = 0.6, linetype = "dashed") +
geom_line(aes(y = hp, colour = "HP trend"), linewidth = 1.0) +
geom_line(aes(y = mbh, colour = "MBH trend"), linewidth = 1.1) +
annotate("rect",
xmin = 2020.00, xmax = 2020.75,
ymin = -Inf, ymax = Inf,
alpha = 0.12, fill = "firebrick") +
annotate("text",
x = 2020.375, y = Inf, vjust = 1.4,
label = "COVID-19\n2020 Q2", size = 3.2, colour = "firebrick") +
scale_colour_manual(
values = c("Observed" = "grey60", "HP trend" = "#0072B2", "MBH trend" = "#E69F00")
) +
facet_wrap(~country, scales = "free_y") +
labs(
title = "HP vs MBH under a Structural Shock",
subtitle = "MBH trend (orange) stays smooth;\nHP trend (blue) is pulled down by the COVID crash",
x = "Year", y = "Log Real GDP", colour = NULL
) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom", strip.text = element_text(face = "bold"))
## ----s3-print-----------------------------------------------------------------
mbh_res
## ----s3-access----------------------------------------------------------------
# Trend and cycle as plain vectors
head(mbh_res$trend, 8)
head(mbh_res$cycle, 8)
# Verify the fundamental identity: trend + cycle == data
max(abs((mbh_res$trend + mbh_res$cycle) - mbh_res$data)) # should be < 1e-9
## ----s3-meta------------------------------------------------------------------
str(mbh_res$meta)
## ----cycle-comparison, fig.height=5-------------------------------------------
df_cycle <- data.frame(
t = as.numeric(time(gdp)),
HP_cycle = as.numeric(hp_res$cycle),
MBH_cycle = as.numeric(mbh_res$cycle)
)
ggplot(df_cycle, aes(x = t)) +
geom_hline(yintercept = 0, linetype = "dashed", colour = "grey40") +
geom_line(aes(y = HP_cycle, colour = "HP cycle"), linewidth = 0.8) +
geom_line(aes(y = MBH_cycle, colour = "MBH cycle"), linewidth = 0.8) +
annotate("rect",
xmin = 2020.00, xmax = 2020.75,
ymin = -Inf, ymax = Inf,
alpha = 0.12, fill = "firebrick") +
scale_colour_manual(values = c("HP cycle" = "#0072B2", "MBH cycle" = "#E69F00")) +
labs(
title = "Cyclical Components",
subtitle = "HP cycle absorbs the shock; MBH cycle faithfully records it",
x = "Year", y = "Cycle", colour = NULL
) +
theme_minimal(base_size = 12) +
theme(legend.position = "bottom")
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.