library(tidyverse)
<- R4ER2data::gdp_br
gdp_br
<- ts(gdp_br$gdp, start = first(gdp_br$quarter), frequency = 4) gdp_br_ts
8 Hodrick-Prescott Filter
In many economic applications, it is necessary to decompose a time series into trend and cycle components in order to relate the observed data to its theoretical counterpart. A classic example is the GDP series, where the trend component is often used as the empirical counterpart to potential GDP, and the cycle component as the empirical counterpart to the output gap. In other applications, decomposition may be used simply to smooth a time series by removing transitory events.
There are several statistical filters that perform this task, the best known being the Hodrick-Prescott filter. The HP filter requires only a single parameter, \(\lambda\), which controls the sensitivity of the trend to short-term fluctuations. The rule of thumb is to use \(\lambda = 1600\) for quarterly data, \(\lambda = 14400\) for monthly data, and \(\lambda = 100\) for yearly data. The hpfilter
function from the mFilter
package implements the HP Filter with default values for \(\lambda\) determined by the frequency of the time series object (ts
class).
To see how it works in practice, let’s use data on Brazilian GDP provided by IBGE. Next, we need to convert it into a ts
object, since this is the default input format required by hpfilter
function.
The Brazilian GDP data set from IBGE is available in the R4ER2data
package under the name gdp_br
.
library(forecast)
|>
gdp_br_ts autoplot() +
labs(
title = 'Brazilian Quarterly GDP (Index: 1995 = 100)',
x = '',
y = 'Brazilian Quarterly GDP (Index: 1995 = 100)'
)
Since the HP filter is not explicitly designed to handle seasonality, I first remove the seasonal component using the automatic selection model provided by the seas
function. The remaining code simply applies the HP filter to the GDP time series and arranges the relevant output into a data frame.
library(seasonal)
library(mFilter)
<- final(seas(gdp_br_ts))
gdp_br_sa <- hpfilter(gdp_br_sa)
gdp_br_hp <- tibble(
hp_out 'quarter' = gdp_br$quarter,
'cycle' = gdp_br_hp$cycle |> c(),
'trend' = gdp_br_hp$trend |> c()
)
|>
hp_out pivot_longer(-quarter, names_to = 'var', values_to = 'value') |>
ggplot(aes(x = quarter)) +
geom_line(aes(y = value), lwd = 1) +
facet_wrap(~ var, scales = 'free_y', ncol = 1) +
labs(
title = 'HP-Filter decomposition of Brazilian GDP',
x = '',
y = ''
)
Despite its widespread use and popularity, the HP filter receives mixed reviews. Perhaps the best-known issue is the end-point bias, whose most common workaround is to add projections to the end of the series before applying the filter. We won’t delve into the pros and cons of the HP filter, as that it beyond the scope of this book. Hamilton (2017) formalized several of those concerns and proposed a new filter intended to overcome all of them. According to the author:
“A regression of the variable at date \(t+h\) on the four most recent values as of date \(t\) offers a robust approach to detrending that achieves all the objectives sought by users of the HP filter with none of its drawbacks.”
The fitted values and residuals from the equation below provide, respectively, the trend and cycle components of the Hamilton filter. As a practical guide, Hamilton suggested using \(h=8\) for quarterly data. Nonetheless, some series may require longer periods \(h\) or more lags \(k\) for the filter to be effective.
\[ y_{t+h} = \alpha + \sum_{p=1}^{4} \beta_p y_{t+1-p} \]
We can apply Hamilton’s filter by estimating the equation above and organizing the corresponding output into a data frame, just as we did with the HP filter. The augment
function from the broom
package does an excellent job of converting the output from an lm
object into a data frame.
<- tibble(
gdp_br_hamilton quarter = gdp_br$quarter,
gdp_sa = gdp_br_sa |> c()
|>
) mutate(
y = gdp_sa,
y1 = lag(gdp_sa, 8),
y2 = lag(gdp_sa, 9),
y3 = lag(gdp_sa, 10),
y4 = lag(gdp_sa, 11)
) <- lm(y ~ y1 + y2 + y3 + y4, gdp_br_hamilton)
hamilton_filter
<- hamilton_filter |>
hamilton_out ::augment() |>
broommutate(quarter = gdp_br_hamilton$quarter[as.numeric(.rownames)]) |>
select(quarter, trend = .fitted, cycle = .resid)
|>
hamilton_out pivot_longer(-quarter, names_to = 'var', values_to = 'value') |>
ggplot(aes(x = quarter)) +
geom_line(aes(y = value), lwd = 1) +
facet_wrap(~ var, scales = 'free_y', ncol = 1) +
labs(
title = 'Hamilton-Filter decomposition of Brazilian GDP',
subtitle = 'h = 8',
x = '',
y = ''
)
We can observe a sharp drop-and-rise in the final part of the output series, which is at odds with what we would expect from a trend component. This issue can be resolved by setting \(h = 12\) (note that \(h\) should be a multiple of the time series frequency). The new plot is shown below.
<- tibble(
gdp_br_hamilton2 quarter = gdp_br$quarter,
gdp_sa = gdp_br_sa |> c()
|>
) mutate(
y = gdp_sa,
y1 = lag(gdp_sa, 12),
y2 = lag(gdp_sa, 13),
y3 = lag(gdp_sa, 14),
y4 = lag(gdp_sa, 15)
)
<- lm(y ~ y1 + y2 + y3 + y4, gdp_br_hamilton2)
hamilton_filter2
<- hamilton_filter2 |>
hamilton_out2 ::augment() |>
broommutate(quarter = gdp_br_hamilton2$quarter[as.numeric(.rownames)]) |>
select(quarter, trend = .fitted, cycle = .resid)
|>
hamilton_out2 pivot_longer(-quarter, names_to = 'var', values_to = 'value') |>
ggplot(aes(x = quarter)) +
geom_line(aes(y = value), lwd = 1) +
facet_wrap(~ var, scales = 'free_y', ncol = 1) +
labs(
title = 'Hamilton-Filter decomposition of Brazilian GDP',
subtitle = 'h = 12',
x = '',
y = ''
)
<- hamilton_out2 |>
final_out mutate(type = 'Hamilton') |>
bind_rows(
|>
hp_out mutate(type = 'HP')
)
|>
final_out pivot_longer(-c(quarter, type), names_to = 'var', values_to = 'value') |>
ggplot(aes(x = quarter)) +
geom_line(aes(y = value, color = type), lwd = 1) +
facet_wrap(~ var, scales = 'free_y', ncol = 1) +
theme(legend.position = 'top') +
labs(
title = 'Trend-Cycle Decomposition of Brazilian GDP',
x = '',
y = '',
color = ''
)
Which one should we choose in this case? From a statistical point of view, the HP filter produced a smoother path for the trend component and a desirable stationary behavior for the cycle component. Nevertheless, economic theory suggests a link between the cycle component of the GDP and inflation. Thus, a common strategy is to evaluate what measure better explains (core) inflation during the period. Alternatively, other developments in the economy might favor the choice of one measure over the other. Ultimately, it is up to the analyst to decide which one best represents their view of the economy’s evolution during that time.