knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)

\begin{figure}[h] \centering \includegraphics[width = 12cm]{bHP_illustration} \caption*{Illustration of bHP, by Iris Shi} \end{figure}

library(bHP)
library(magrittr)

Introduction

This vignette introduces the HP filter, the boosted HP filter, and the usage of the R package bHP. The Hodrick-Prescott filter (HP filter; @hodrick1997postwar) is one of the fundamental statistical tools in macroeconomic data analysis. Thanks to its simplicity, it has been widely used in empirical macroeconomics studies. As an operational algorithm, its pros and cons have been debated over decades, and academic interest has been renewed in recent years to investigate its properties and extensions. While @hamilton2017you argues against the usage of the HP filter, @Phillips2019boosting propose a machine learning enhancement of the original HP filter, called the boosted HP filter (bHP), and establish consistency when it is applied to a large class of trended time series in macroeconomic applications.

HP filter

Given a time series $(x_{t}){t=1}^n$ the HP method decomposes it into two additive components: a trend component $f{t}$ and a cyclical component (residual) $c_{t}$. The trend is estimated as [ (\hat{f}{t}^\mathrm{HP} ) =\arg\min{ (f_{t} )} \left{ \sum_{t=1}^{n} (x_{t}-f_{t} )^{2} +\lambda\sum_{t=2}^{n} (\Delta^ 2 f_{t} )^{2} \right}, ] where $\Delta f_{t}=f_{t}-f_{t-1}$, and $\Delta^2 f_{t}= \Delta f_{t}- \Delta f_{t-1} = f_{t}- 2 f_{t-1} + f_{t-2}$, and $\lambda\geq 0$ is a tuning parameter that controls the level of the penalty. The corresponding cycle is [ (\hat{c}{t}^\mathrm{HP} )=( x_t-\hat{f}{t}^\mathrm{HP}). ]

The optimization problem admits a closed form solution. The estimated trend can be written as \begin{equation} \widehat{f}^{\mathrm{HP}}=S x, \end{equation} where $S$ is a deterministic $n\times n$ matrix and $x=(x_1,...,x_n)'$ is the sample data. The estimated trend is [ \widehat{c}^{\mathrm{HP}}=\left(I_{n}-S\right)x, ] where $I_{n}$ is the $n\times n$ identity matrix. The explicit form of $S$ can be found in @Phillips2019boosting.

The choice of the tuning parameter is crucial for the behavior of the HP filter. In practice, @hodrick1997postwar recommend $\lambda=1600$ for quarterly data, and this number and its sampling frequency adjusted version [@ravn2002adjusting] are widely adopted. However, recent research [@phillips2015business] [@hamilton2017you] find the "gold standard" is too rigid for the length of time series that often used in macroeconomic studies.

Boosted HP filter

The intuition of bHP is that, if the cyclical component $\widehat{c}{t}^{\mathrm{HP}}$ still exhibits trending behavior after HP filtering, we continue to apply the HP filter to $\widehat{c}^{\mathrm{HP}}$ to remove the leftover trend residual. After a second fitting, the cyclical component can be written as [ \widehat{c}^{\left(2\right)}=\left(I{n}-S\right)\widehat{c}^{\mathrm{HP}}=\left(I_{n}-S\right)^{2}x, ] where the superscript ``$\left(2\right)$'' indicates that the HP filter is fitted twice. The corresponding trend component becomes [ \widehat{f}^{\left(2\right)}=x-\widehat{c}^{\left(2\right)}=\left(I_{n}-\left(I_{n}-S\right)^{2}\right)x. ] If $\widehat{c}^{\left(2\right)}$ continues to exhibit trend behavior, the filtering process may be continued for a third or further time. After $m$ repeated applications of the filter, the cyclical and trend component are \begin{eqnarray} \widehat{c}^{\left(m\right)} & = & \left(I_{n}-S\right)\widehat{c}^{\left(m-1\right)}=\left(I_{n}-S\right)^{m}x \ \widehat{f}^{\left(m\right)} & = & x-\widehat{c}^{\left(m\right)}. \end{eqnarray}

The number of iterations $m$ is an additional tuning parameter in bHP. In practice, it is recommended that we choose $\lambda$ according to the convention, say $\lambda = 1600$ for quarterly data, and then monitor a stopping criterion as the iteration proceeds. @Phillips2019boosting suggest using either the ADF test or the Bayesian Information Criterion (BIC) to terminate the iteration.

This package bHP automates bHP. The main function is BoostedHP. The user chooses the two tuning parameters lambda for $\lambda$ and stopping for the stopping criterion. In particular, three options are available for stopping:

The basic usage with the default options is as follows:

BoostedHP(x, lambda = 1600, iter= TRUE, stopping = "BIC", Max_Iter = 100)

The above line produces an object of the bHP class. We can extract the trend by $trend, the cycle by $cycle. The sequence of trend for each iteration is stored in $trend_hist, and $iter_num reports the number of iterations. The original HP filter can also be implemented by setting iter = FALSE along with a lambda.

Examples

One of the applications in @Phillips2019boosting is concerning the international comparison of the Okun's law. We use Ireland's annual GDP here for illustration.

lam <- 100 # tuning parameter for the annual data
data(IRE) # load the data 'IRE'

bx_HP <- BoostedHP(IRE, lambda = lam, iter= FALSE)$trend
bx_BIC <- BoostedHP(IRE, lambda = lam, stopping = "BIC")$trend
bx_ADF <- BoostedHP(IRE, lambda = lam, stopping = "adf")$trend
bx_nonstop <- BoostedHP(IRE, lambda = lam, iter= TRUE, 
                        stopping = "nonstop") %>% predict( )
# use the generic method `predict` is an alternative way to get the trend

matplot( y = cbind(IRE, bx_HP, bx_BIC, bx_ADF, bx_nonstop), 
         type = "l", x = 1981:2016, ylab = "data and trends", 
         xlab = "year", main = "Ireland Annual GDP")
legend("bottomright", legend = c("data","HP", "BIC", "ADF", "nonstop"), 
       col = 1:5, lty = 1:5)

The trend and cycle can also be extracted by the generic methods predict and residuals, respectively.

bx <- BoostedHP(IRE, lambda = lam, stopping = "BIC")
IRE_cycle <- residuals(bx)

Version

This is our first R package released on github, labeled with Version 1.0. The main function BoostedHP and associated methods predict, residuals and BIC are complete and well documented. The package also contains experimental generic methods print, plot and summary, which are still preliminary.

#-------- plot -----------

?plot.bHP

#--------- start to plot the content of bHP -----------------

#--------- for dynamic style (default)--------
plot(bx_ADF)

plot(bx_ADF, iteration_location = "upright") # change the location of text

plot(bx_ADF, iteration_location = c(30,12)) # assign the location of text by x-y co-ordinates

plot(bx_BIC, interval_t = 0.8 ) # change the time interval of animation

plot(bx_nonstop, cex_legend = 2, cex_text = 3) # change the magnification of legend and text

# change the color
plot(bx_ADF,main = "dynamic graph with new color",col_raw = "#685F74", col_trend_h = "#39A1A8", col_trend_f = "#DD4B4F", col_pvalue_BIC = "#E96145")

plot(bx_ADF,main = "dynamic graph with new trancparency setting",raw_alpha = 200, trend_h_alpha = 55, trend_f_alpha = 250, pvalue_BIC_alpha = 250)

plot(bx_HP)
# nonstop-iter' bHP doesn't have dynamic picture: returning NA

#--------- for JS style ----------

plot(bx_ADF,plot_type = "JS")

# change the color
plot(bx_ADF,plot_type = "JS",main = "Js graph with new color", col_raw = "#685F74", col_trend_f = "#DD4B4F", col_pvalue_BIC = "#39A1A8")

plot(bx_BIC,plot_type = "JS")

plot(bx_nonstop,plot_type = "JS")

plot(bx_HP,plot_type = "JS")

#--------- for static style ----------

plot(bx_ADF,plot_type = "static",cex_legend = 0.7, cex_text = 0.8 )

plot(bx_HP,plot_type = "static")

plot(bx_BIC,plot_type = "static",cex_legend = 0.7, cex_text = 0.8 )

plot(bx_nonstop,plot_type = "static",cex_legend = 0.8, cex_text = 0.8 )

#----------- print -------------------------------

?print.bHP

#--------- start to print the content of bHP -----------------
print(bx_ADF)

print(bx_ADF, Head = F, Tail = T, trend_hist = F)

print(bx_ADF, Head = T, Tail = T, trend_hist = F)

print(bx_ADF, Head = F, Tail = F, trend_hist = F)

print(bx_BIC, Head = F, Tail = F, trend_hist = T, select_trend_hist = 1:bx_BIC$iter_num)

print(bx_BIC, Head = F, Tail = F, trend_hist = T,  select_trend_hist = c(1,3,5))

# when the trend_hist is FALSE, select_trend_hist is invalid
print(bx_BIC, Head = F, Tail = F, trend_hist = F, select_trend_hist = c(1,3,5))

print(bx_BIC, Head = F, Tail = T, trend_hist = F, print_type = "latex")

print(bx_BIC, Head = F, Tail = T, trend_hist = F, print_type = "html")

# show the generic print function output
print(bx_ADF, type = "generic default")



#------------------ summary -----------------

?summary.bHP

summary(bx_ADF)
summary(bx_BIC)
summary(bx_nonstop)
summary(bx_HP)

#------------------ predict -----------------

?predict.bHP

predict(bx_HP) #Iterated number of HP filter: 1

predict(bx_ADF) #Iterated number of HP filter: 19

predict(bx_BIC) #Iterated number of HP filter: 5

predict(bx_nonstop) #Iterated number of HP filter: 99


#------------------ residuals -----------------

?residuals.bHP

residuals(bx_HP) #Iterated number of HP filter: 1

residuals(bx_ADF) #Iterated number of HP filter: 19

#------------------ BIC -------------------------

?BIC.bHP

BIC(bx_BIC)

#Retrun the value path of BIC.
#Iterated number of HP filter: 5
#Keep the path of BIC till iterated 6 times to show the tuning point.
#[1] 1.586255 1.366335 1.293931 1.264323 1.254397 1.254620

BIC(bx_nonstop)

#Retrun the BIC path of nonstop.
#Iterated number of HP filter: 99
#Keep the path of BIC till iterated 100 times to show the tuning point.
#[1] 1.586255 1.366335 1.293931 1.264323 1.254397 1.254620 1.260345 1.269139 1.279670 1.291179
#[11] 1.303223 ...


### If the test type is not "adf", Pvalue.bHP will return error

# raw HP filter
BIC(bx_HP)

# Error in BIC.bHP(bx_HP) :
# The stationary test type is nonstop-iter, not BIC or nonstop.


# by ADF
BIC(bx_ADF)

#Error in BIC.bHP(bx_ADF) :
#The stationary test type is adf, not BIC or nonstop.

References



chenyang45/BoostedHP documentation built on Nov. 12, 2022, 11:36 a.m.