diff --git a/docs/404.html b/docs/404.html index 801ccdf..c43aa96 100644 --- a/docs/404.html +++ b/docs/404.html @@ -67,7 +67,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/articles/Getting-started.html b/docs/articles/Getting-started.html index 38262ee..0b80e67 100644 --- a/docs/articles/Getting-started.html +++ b/docs/articles/Getting-started.html @@ -31,7 +31,7 @@ neverhpfilter - 0.3.0 + 0.3.1 @@ -92,15 +92,15 @@

Justin M Shea

Introduction

-

The neverhpfilter package consists of 2 functions, 12 economic data sets, Robert Shiller’s U.S. Stock Markets and CAPE Ratio data from 1871 through 2019, and a data.frame containing the original filter estimates found on table 2 of Hamilton (2017) <doi:10.3386/w23429>. All data objects are stored as .Rdata files in eXtensible Time Series (xts) format.

-

One of the first things to know about the neverhpfilter package is that it’s functions accept and output, xts objects. The author uses xts often as it remains one of the most efficient data objects for managing times series data in econometrics and finance.

-

An xts object is a list consisting of a vector index of some date/time class paired with a matrix object of singular data type. In our case, type numeric. data.table is also heavily used in finance and has efficient date/time indexing capabilities as well. It is useful when working with large data.frame like lists containing vectors of multiple data types of equal length. If using data.table or some other index based time series data object, merging the xts objects created by functions of this package into your preferred data object should be fairly easy. Note xts is a dependency listed under the “Suggests” field of data.table DESCRIPTION file.

-

For more information on xts objects, go here and here.

+

The neverhpfilter package consists of 2 functions, 12 economic data sets, Robert Shiller’s U.S. Stock Market and CAPE Ratio data from 1871 through 2019, and a data.frame containing the original filter estimates found on table 2 of Hamilton (2017) <doi:10.3386/w23429>. All data objects are stored as .Rdata files in eXtensible Time Series (xts) format.

+

One of the first things to know about the neverhpfilter package is that it’s functions accept and output, xts objects.

+

An xts object is a list consisting of a vector index of some date/time class paired with a matrix object containing data of type numeric. data.table is also heavily used in finance and has efficient date/time indexing capabilities as well. It is useful when working with large data.frame like lists containing vectors of multiple data types of equal length. If using data.table or some other index based time series data object, merging the xts objects created by functions of this package should be fairly easy. Note xts is a dependency listed under the “Suggests” field of data.table DESCRIPTION file.

+

For more information on xts objects, go here and here.

yth_glm

-

The yth_glm function primarily exists to model the output for the yth_filter. However, one can use this wrapper around glm independently. On that note, the function API allows you to use the ... to pass any additional arguments to glm.

-

The yth_filter returns an object of class glm, so one can use all generic methods associated with objects of that class. Here is an example of passing the results of a yth_glm model to the plot function, which outputs the standard plot diagnostics associated with the method.

+

The yth_glm function wraps glm and primarily exists to model the output for the yth_filter. On that note, the function API allows one to use the ... to pass any additional arguments to glm.

+

The yth_filter returns an object of class glm, so one can use all generic methods associated with glm objects. Here is an example of passing the results of a yth_glm model to the plot function, which outputs the standard plot diagnostics associated with the method.

library(neverhpfilter)
 
 data(GDPC1)
@@ -115,7 +115,7 @@ 

yth_filtered

-

This is the main function of the package and both accepts, and outputs an xts object. The resulting output contains various series discussed in Hamilton (2017). These are a user defined combination of the original, trend, cycle, and random walk series. See documentation and the original paper for further details.

+

This is the main function of the package. It both accepts and outputs xts objects. The resulting output contains various series discussed in Hamilton (2017). These are a user defined combination of the original, trend, cycle, and random walk series. See documentation and the original paper for further details.

gdp_filtered <- yth_filter(log_RGDP, h = 8, p = 4)
 
 tail(gdp_filtered, 16)
@@ -138,8 +138,8 @@

## 2019 Q4 986.3695 985.7645 0.60492133 4.781143

class(gdp_filtered)
## [1] "xts" "zoo"
-

The output is an xts object, it inherits all generic methods and capabilities associated with xts. For example, one can conveniently produce clean times series graphics with plot.xts.

-

Not the use of xts::addPanel function, which adds a panel plot of the cycle output of the yth_filter to the original graph.

+

As the output is an xts object, it inherits all generic methods associated with xts. For example, one can conveniently produce clean time series graphics with plot.xts.

+

Not the use of xts::addPanel function, which is used to panel plot the cycle component of the yth_filter.

plot(log_RGDP, grid.col = "white", col = "blue", legend.loc = "topleft", main = "100 x Log of Real GDP (GDPC1)")

addPanel(yth_filter, output=c("cycle"), type="h", on=NA, col="darkred" )
@@ -148,7 +148,8 @@

Choices for h and p

-

In the paper that inspired this package, Hamilton converts the PAYEMS series into quarterly periodicity and then uses filters on the transformed time series. With the yth_filter function, one can choose to retain the monthly series and adjust the h and p parameters accordingly. The default parameters of h = 8 and p = 4 assume times series data of a quarterly periodicity. For time series of monthly periodicity, one can retain the same look-ahead and lag periods with h = 24 and p = 12. See the yth_filter documentation for more details.

+

In the original paper, Hamilton aggregates the PAYEMS monthly employment series into data of quarterly periodicity prior to apply his filter. That is a desirable approach when comparing with other economic series of quarterly periodicity. However, using the yth_filter function, one can choose to retain the monthly series and adjust the h and p parameters accordingly.

+

The default parameters of h = 8 and p = 4 assume times series data of a quarterly periodicity. For time series of monthly periodicity, one can retain the same look-ahead and lag periods with h = 24 and p = 12. See the yth_filter documentation for more details.

Employment_log <- 100*log(PAYEMS["1950/"])
 
 employment_cycle <- yth_filter(Employment_log, h = 24, p = 12, output = "cycle")
@@ -156,7 +157,7 @@ 

plot(employment_cycle, grid.col = "white", type = "h", up.col = "darkgreen", dn.col = "darkred", main = "Log of Employment cycle")

-

In addition to adjust for various periodicities, one may wish to consider longer term cycles by extending h. Below are examples of moving the look-ahead period defined by h from 8 quarters (2 years), to 20 quarters (5 years), and then 40 quarters (10 years).

+

In addition to adjusting parameters to accommodate other periodicities, one may wish to explore longer term cycles by extending h. Below are examples of moving the look-ahead period defined by h from 8 quarters (2 years), to 20 quarters (5 years), and then 40 quarters (10 years).

gdp_5yr <- yth_filter(log_RGDP, h = 20, p = 4, output = c("x", "trend", "cycle"))
 
 plot(gdp_5yr["1980/"][,1:2], grid.col = "white", legend.loc = "topleft", 
@@ -173,7 +174,7 @@ 

Conclusion

-

These functions give you the option to, in the words of Hamilton, never use the Hodrick-Prescott filter.They identify a more stable trend component that doesn’t have the estimation issues associated with the head and tail portions of components generated by the HP filter.

+

These functions give you an avenue to filter econometric time series into trend and cycle components. They identify a more stable trend and cycle components that doesn’t have the estimation issues associated with the head and tail portions of those generated by the HP-filter.

diff --git a/docs/articles/Reproducing-Hamilton.html b/docs/articles/Reproducing-Hamilton.html index b855f82..a322c30 100644 --- a/docs/articles/Reproducing-Hamilton.html +++ b/docs/articles/Reproducing-Hamilton.html @@ -31,7 +31,7 @@ neverhpfilter - 0.3.0 + 0.3.1

@@ -103,7 +103,7 @@

Justin M Shea

  • There’s a better alternative. 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.
  • -

    Using quarterly economic data, Hamilton suggests a linear model dependent on an h = 8 look-ahead period, which is independent of p = 4 lagged variables. An auto-regressive \(AR(p)\) model, dependent on \(t+h\) look-ahead, if you will. This is expressed more specifically by:

    +

    Using quarterly economic data, Hamilton suggests a linear model on a univariate time series shifted ahead by some period h, regressed against a series of variables constructed form lagging the same series by some number of periods, p. An auto-regressive \(AR(p)\) model, dependent on a \(t+h\) look-ahead, if you will. This is expressed more specifically by:

    \[y_{t+8} = \beta_0 + \beta_1 y_t + \beta_2 y_{t-1} +\beta_3 y_{t-2} + \beta_4 y_{t-3} + v_{t+8}\] \[\hat{v}_{t+8} = y_{t+8} + \hat{\beta}_0 + \hat{\beta}_1 y_t + \hat{\beta}_2 y_{t-1} + \hat{\beta}_3 y_{t-2} + \hat{\beta}_4 y_{t-3}\]

    Which can be rewritten as:

    \[y_{t} = \beta_0 + \beta_1 y_{t-8} + \beta_2 y_{t-9} + \beta_3 y_{t-10} + \beta_4 y_{t-11} + v_{t}\]

    @@ -111,525 +111,146 @@

    Justin M Shea

    Implementation

    -

    First, lets run the yth_filter on Real GDP using the default settings suggested by Hamilton of an \(h = 8\) lookahead period and \(p = 4\) lags. The output is displayed below containing the original series, trend, cycle, and random components.

    +

    First, lets run the yth_filter on Real GDP using the default settings suggested by Hamilton of an \(h = 8\) look-ahead period (2 years) and \(p = 4\) lags (1 year). The output is displayed below containing the original series, trend, cycle, and random components.

    The random component is simply the difference between the original series and its \(h\) look ahead, which is why it leads 8 NA observations. Due to the \(h\) and \(p\) parameters, trend and cycle components lead with 11 NA observations.

    -
    library(xts)
    -library(knitr)
    -library(neverhpfilter)
    +
    library(neverhpfilter)
    data(GDPC1)
     
     gdp_filter <- yth_filter(100*log(GDPC1), h = 8, p = 4)
     
    -kable(head(data.frame(Date=index(gdp_filter), coredata(gdp_filter)), 15), align = 'l')
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    DateGDPC1GDPC1.trendGDPC1.cycleGDPC1.random
    1947 Q1761.7298NANANA
    1947 Q2761.4627NANANA
    1947 Q3761.2560NANANA
    1947 Q4762.8081NANANA
    1948 Q1764.3012NANANA
    1948 Q2765.9384NANANA
    1948 Q3766.5096NANANA
    1948 Q4766.6213NANANA
    1949 Q1765.2338NANA3.503988
    1949 Q2764.8921NANA3.429356
    1949 Q3765.9192NANA4.663188
    1949 Q4765.0764772.3598-7.28339962.268271
    1950 Q1768.9313773.5218-4.59058004.630074
    1950 Q2771.9355774.6608-2.72526045.997144
    1950 Q3775.7271775.02270.70441089.217473
    +head(data.frame(Date=index(gdp_filter), coredata(gdp_filter)), 15)
    +
    ##       Date    GDPC1 GDPC1.trend GDPC1.cycle GDPC1.random
    +## 1  1947 Q1 761.7298          NA          NA           NA
    +## 2  1947 Q2 761.4627          NA          NA           NA
    +## 3  1947 Q3 761.2560          NA          NA           NA
    +## 4  1947 Q4 762.8081          NA          NA           NA
    +## 5  1948 Q1 764.3012          NA          NA           NA
    +## 6  1948 Q2 765.9384          NA          NA           NA
    +## 7  1948 Q3 766.5096          NA          NA           NA
    +## 8  1948 Q4 766.6213          NA          NA           NA
    +## 9  1949 Q1 765.2338          NA          NA     3.503988
    +## 10 1949 Q2 764.8921          NA          NA     3.429356
    +## 11 1949 Q3 765.9192          NA          NA     4.663188
    +## 12 1949 Q4 765.0764    772.3598  -7.2833996     2.268271
    +## 13 1950 Q1 768.9313    773.5218  -4.5905800     4.630074
    +## 14 1950 Q2 771.9355    774.6608  -2.7252604     5.997144
    +## 15 1950 Q3 775.7271    775.0227   0.7044108     9.217473

    Comparing our estimates with Hamilton’s

    In this next section, I reproduce a few of Hamilton’s tables and graphs, to make sure the functions approximately match his results.

    In the Appendix, Employment (All Employees: Total Non-farm series) is plotted in the form of \(100 * log(\)PAYEMS\()\) and superimposed with it’s random walk representation. (Hamilton 44). There are many good reasons to use xts when handling time series data. Two of them are illustrated below in efficiently transforming monthly series to.quarterly and in ploting the results of yth_filter.

    -
    data(PAYEMS)
    -log_Employment <- 100*log(xts::to.quarterly(PAYEMS["1947/2016-6"], OHLC = FALSE))
    -
    -employ_trend <- yth_filter(log_Employment, h = 8, p = 4, output = c("x", "trend"), family = gaussian)
    -
    -plot.xts(employ_trend, grid.col = "white", legend.loc = "topleft", main = "Log of Employment and trend")
    +
    data(PAYEMS)
    +log_Employment <- 100*log(xts::to.quarterly(PAYEMS["1947/2016-6"], OHLC = FALSE))
    +
    +employ_trend <- yth_filter(log_Employment, h = 8, p = 4, output = c("x", "trend"), family = gaussian)
    +
    +plot.xts(employ_trend, grid.col = "white", legend.loc = "topleft", main = "Log of Employment and trend")

    When filtering time series, the cycle component is of great interest. Here, it is graphed alongside a random walk representation (Hamilton 44).

    -
    employ_cycle <- yth_filter(log_Employment, h = 8, p = 4, output = c("cycle", "random"), family = gaussian)
    -
    -plot.xts(employ_cycle, grid.col = "white", legend.loc = "topright", main="Log of Employment cycle and random")
    -abline(h=0)
    +

    Turning the page, we find a similar graph of the cyclical component of \(100 * log\) of GDP, Exports, Consumption, Imports, Investment, and Government (Hamilton 45).

    Below I merge these data into one xts object and write a function wrapper around yth_filter and plot, which is then lapply’d over each series, producing a plot for each one.

    -
    fig6_data <- 100*log(merge(GDPC1, EXPGSC1, PCECC96, IMPGSC1, GPDIC1, GCEC1)["1947/2016-3"])
    -
    -fig6_wrapper <- function(x, ...) {
    -               cycle <-  yth_filter(x, h = 8, p = 4, output = c("cycle", "random"), family = gaussian)
    -               plot.xts(cycle, grid.col = "white", lwd=1, main = names(x))
    -}
    -
    par(mfrow=c(3,2))
    -lapply(fig6_data, fig6_wrapper)
    +
    fig6_data <- 100*log(merge(GDPC1, EXPGSC1, PCECC96, IMPGSC1, GPDIC1, GCEC1)["1947/2016-3"])
    +
    +fig6_wrapper <- function(x, ...) {
    +               cycle <-  yth_filter(x, h = 8, p = 4, output = c("cycle", "random"), family = gaussian)
    +               plot.xts(cycle, grid.col = "white", lwd=1, main = names(x))
    +}
    +
    par(mfrow=c(3,2))
    +lapply(fig6_data, fig6_wrapper)

    -

    When striving to recreate a statistical method found in a journal or paper, one can perform surprisingly well by thoroughly digesting the relevant sections and “eyeballing” graphs included in the authors work.

    -

    Better still, is a table presenting the authors results, which one may use to directly compare with their own reproduction. Fortunately for us, Hamilton’s Appendix displays such a table which I use to test against estimates computed with functions contained in neverhpfilter.

    +

    When striving to recreate a statistical method found in a journal or paper, one can perform surprisingly well by thoroughly digesting the relevant sections and “eyeballing” graphs included in the original author’s work.

    +

    Better still, is finding a table presenting said author’s estimates, which one can use to directly compare with their own. Fortunately for us, Hamilton’s Appendix displays such a table which I use here to test against functions contained in neverhpfilter.

    His results are displayed below in table 2 (Hamilton 40), which I’ve stored as a data.frame in this package.

    -
    data("Hamilton_table_2")
    -?Hamilton_table_2
    -
    kable(Hamilton_table_2[-NROW(Hamilton_table_2),], align = 'l', caption = "Hamilton's results: table 2, pg. 40")
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Hamilton’s results: table 2, pg. 40
    cycle.sdgdp.corrandom.sdgdp.rand.corSample
    GDP3.381.003.691.001947-1/2016-1
    Consumption2.850.793.040.821947-1/2016-1
    Investment13.190.8413.740.801947-1/2016-1
    Exports10.770.3311.330.301947-1/2016-1
    Imports9.790.779.980.751947-1/2016-1
    Government-spending7.130.318.600.381947-1/2016-1
    Employment3.090.853.320.851947-1/2016-2
    Unemployment-rate1.44-0.811.72-0.791948-1/2016-2
    GDP-Deflator2.990.044.11-0.131947-1/2016-1
    S&P50021.800.4122.080.381950-1/2016-2
    10-year-Treasury-yield1.46-0.051.510.081953-2/2016-2
    Fedfunds-rate2.780.333.030.401954-3/2016-2
    +
    data("Hamilton_table_2")
    +?Hamilton_table_2
    +
    Hamilton_table_2[-NROW(Hamilton_table_2),]
    +
    ##                        cycle.sd gdp.cor random.sd gdp.rand.cor        Sample
    +## GDP                        3.38    1.00      3.69         1.00 1947-1/2016-1
    +## Consumption                2.85    0.79      3.04         0.82 1947-1/2016-1
    +## Investment                13.19    0.84     13.74         0.80 1947-1/2016-1
    +## Exports                   10.77    0.33     11.33         0.30 1947-1/2016-1
    +## Imports                    9.79    0.77      9.98         0.75 1947-1/2016-1
    +## Government-spending        7.13    0.31      8.60         0.38 1947-1/2016-1
    +## Employment                 3.09    0.85      3.32         0.85 1947-1/2016-2
    +## Unemployment-rate          1.44   -0.81      1.72        -0.79 1948-1/2016-2
    +## GDP-Deflator               2.99    0.04      4.11        -0.13 1947-1/2016-1
    +## S&P500                    21.80    0.41     22.08         0.38 1950-1/2016-2
    +## 10-year-Treasury-yield     1.46   -0.05      1.51         0.08 1953-2/2016-2
    +## Fedfunds-rate              2.78    0.33      3.03         0.40 1954-3/2016-2

    I’ll replicate the table above, combining base R functions with estimates of the yth_filter function.

    -

    Per the usual protocol when approaching such a problem, the first step is to combine data in manner that allows for convenient iteration of computations across all data sets. First, I merge series which already have a quarterly frequency. These are GDPC1, PCECC96, GPDIC1, EXPGSC1, IMPGSC1, GCEC1, GDPDEF. At this step, we can also subset observations by the date range used by Hamilton. As all series of which units are measured in prices need to be given the \(100*log\) treatment, I add that to this step as well.

    -
    quarterly_data <- 100*log(merge(GDPC1, PCECC96, GPDIC1, EXPGSC1, IMPGSC1, GCEC1, GDPDEF)["1947/2016-3"])
    -

    Some of the series we wish to compare have a monthly periodicity, so we need to lower their frequency to.quarterly. First, merge monthly series and \(100*log\) those expressed in prices. Leave those expressed in percentages alone. Then, functionally iterate over every series and transform them to.quarterly. Presumably because more data was available at the time of Hamilton’s work, monthly series include observations from the second quarter of 2016 and so I subset accordingly. Finally, all series are combined into one xts object, quarterly_data.

    -
    monthly_data <- merge(100*log(PAYEMS), 100*log(SP500$SP500)["1950/"], UNRATENSA, GS10, FEDFUNDS)
    -
    -to_quarterly_data <- do.call(merge, lapply(monthly_data, to.quarterly, OHLC = FALSE))["1947/2016-6"]
    -
    -quarterly_data <- merge(quarterly_data, to_quarterly_data)
    -

    Now that the data has been prepped, its time to functionally iterate over each series, lapplying the yth_filter to all. The optional argument of output = "cycle" comes in handy because it returns the labeled univariate cycle component for each series. The same can be done for the random component as well.

    -
    cycle <- do.call(merge, lapply(quarterly_data, yth_filter, output = "cycle"))
    -
    -random <- do.call(merge, lapply(quarterly_data, yth_filter, output = "random"))
    -

    Now that all data have been transformed into both cycle and random components, its time to estimate the standard deviation for each, as well as each components correlation with GDP. This is also a good opportunity to transpose each of our estimates into vertical columned data.frames, matching Hamilton’s format.

    -
    cycle.sd <- t(data.frame(lapply(cycle, sd, na.rm = TRUE)))
    -GDP.cor <- t(data.frame(lapply(cycle, cor, cycle[,1], use = "complete.obs")))
    -random.sd <- t(data.frame(lapply(random, sd, na.rm = TRUE)))
    -random.cor <- t(data.frame(lapply(random, cor, random[,1], use = "complete.obs")))
    -
    -my_table_2 <- round(data.frame(cbind(cycle.sd, GDP.cor, random.sd, random.cor)), 2)
    -

    Hamilton displays the date ranges of his samples so we will do the same.

    -

    I use a simple function I call sample_range to extract the first and last observation of each series’ index.xts. This approach serves as a check on the work, as oppose to manually creating labels.

    -

    Sample ranges are then transposed into vertical data.frames and cbind’d to the existing table of estimates.

    -
    sample_range <- function(x) {
    -  x <- na.omit(x)
    -  gsub(" ", "-", paste0(index(x[1,]), "/", index(x[NROW(x),])))
    -}
    -
    -data_sample <- t(data.frame(lapply(quarterly_data, sample_range)))
    -
    -my_table_2 <- cbind(my_table_2, data_sample)
    -names(my_table_2) <- names(Hamilton_table_2)
    -

    Finally, rbind Hamilton’s table 2 with my table and compare. The results are nearly identical, inspiring confidence in the replication of this approach.

    -

    According to the ‘code and data’ link on the ‘Current Working Papers’ page of Hamilton’s site, both Matlab and RATS were used for computation of the table. It is not surprising that minor differences in estimates would occur, likely due to differences in the underlying data or internal computational choices made by each commercial software product.

    -
     # Combined table
    -combined_table <- rbind(Hamilton_table_2[-NROW(Hamilton_table_2),], my_table_2)
    -combined_table <- combined_table[order(combined_table$cycle.sd),]
    -kable(combined_table, align = 'l', caption = "Hamilton's table 2 compared with estimates from neverhpfilter::yth_filter, sorted by standard deviation of the cycle component. yth_filter estimates are labeled with the suffix '.cycle'")
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    Hamilton’s table 2 compared with estimates from neverhpfilter::yth_filter, sorted by standard deviation of the cycle component. yth_filter estimates are labeled with the suffix ‘.cycle’
    cycle.sdgdp.corrandom.sdgdp.rand.corSample
    Unemployment-rate1.44-0.811.72-0.791948-1/2016-2
    UNRATENSA.cycle1.44-0.821.71-0.801948-Q1/2016-Q2
    10-year-Treasury-yield1.46-0.051.510.081953-2/2016-2
    GS10.cycle1.46-0.051.510.081953-Q2/2016-Q2
    Fedfunds-rate2.780.333.030.401954-3/2016-2
    FEDFUNDS.cycle2.780.333.030.411954-Q3/2016-Q2
    PCECC96.cycle2.840.793.020.821947-Q1/2016-Q1
    Consumption2.850.793.040.821947-1/2016-1
    GDP-Deflator2.990.044.11-0.131947-1/2016-1
    GDPDEF.cycle3.000.034.12-0.141947-Q1/2016-Q1
    Employment3.090.853.320.851947-1/2016-2
    PAYEMS.cycle3.090.853.320.851947-Q1/2016-Q2
    GDPC1.cycle3.371.003.651.001947-Q1/2016-Q1
    GDP3.381.003.691.001947-1/2016-1
    Government-spending7.130.318.600.381947-1/2016-1
    GCEC1.cycle7.160.318.590.381947-Q1/2016-Q1
    IMPGSC1.cycle9.750.769.910.751947-Q1/2016-Q1
    Imports9.790.779.980.751947-1/2016-1
    EXPGSC1.cycle10.750.3311.320.301947-Q1/2016-Q1
    Exports10.770.3311.330.301947-1/2016-1
    GPDIC1.cycle13.140.8313.650.781947-Q1/2016-Q1
    Investment13.190.8413.740.801947-1/2016-1
    SP500.cycle21.380.4221.600.401950-Q1/2016-Q2
    S&P50021.800.4122.080.381950-1/2016-2
    +

    The first step is to combine our economic time series into an object that allows for convenient iteration of computations across all data of interest. First, merge all series of quarterly frequency. These are GDPC1, PCECC96, GPDIC1, EXPGSC1, IMPGSC1, GCEC1, GDPDEF. At this point, subset observations by the precise date range used by Hamilton. At some point, all series which are measured in prices need to be given the \(100*log\) treatment, so do this now.

    +
    quarterly_data <- 100*log(merge(GDPC1, PCECC96, GPDIC1, EXPGSC1, IMPGSC1, GCEC1, GDPDEF)["1947/2016-3"])
    +

    Some economic time series we wish to compare are measured in monthly periodicity, so we need to lower their frequency to.quarterly. merge monthly series and \(100*log\) those expressed in prices. Leave data measured in percentages be. Then, functionally iterate over every series and transform them to.quarterly. Finally, all series are combined into one xts object, I call quarterly_data.

    +
    monthly_data <- merge(100*log(PAYEMS), 100*log(SP500$SP500)["1950/"], UNRATENSA, GS10, FEDFUNDS)
    +
    +to_quarterly_data <- do.call(merge, lapply(monthly_data, to.quarterly, OHLC = FALSE))["1947/2016-6"]
    +
    +quarterly_data <- merge(quarterly_data, to_quarterly_data)
    +

    Now its time to functionally iterate over each series. I do this by lapplying the yth_filter to each series, while iteratively mergeing results into one object with do.call. The optional argument of output = "cycle" is convenient here as it returns the labeled univariate cycle component for each series. For example, GDPCE1.cycle. The same approach is use to compute the random component for each series as well.

    +
    cycle <- do.call(merge, lapply(quarterly_data, yth_filter, output = "cycle"))
    +
    +random <- do.call(merge, lapply(quarterly_data, yth_filter, output = "random"))
    +

    Now that all data have been transformed into both cycle and random series, its time to estimate the standard deviation for each, as well as each components correlation with GDP. This is also a good opportunity to transpose each of our estimates into vertical columned data.frames, matching Hamilton’s format.

    +
    cycle.sd <- t(data.frame(lapply(cycle, sd, na.rm = TRUE)))
    +GDP.cor <- t(data.frame(lapply(cycle, cor, cycle[,1], use = "complete.obs")))
    +random.sd <- t(data.frame(lapply(random, sd, na.rm = TRUE)))
    +random.cor <- t(data.frame(lapply(random, cor, random[,1], use = "complete.obs")))
    +
    +my_table_2 <- round(data.frame(cbind(cycle.sd, GDP.cor, random.sd, random.cor)), 2)
    +

    Hamilton displays the date ranges of his samples, so we will do the same, while keeping the xts date range syntax format. I use a simple function I call sample_range to extract the first and last observation of each series’ index.xts. This approach serves as a check on the work, as oppose to manually creating labels. Sample ranges are then transposed into vertical data.frames and cbind’d to the existing table of estimates.

    +
    sample_range <- function(x) {
    +  x <- na.omit(x)
    +  gsub(" ", "-", paste0(index(x[1,]), "/", index(x[NROW(x),])))
    +}
    +
    +data_sample <- t(data.frame(lapply(quarterly_data, sample_range)))
    +
    +my_table_2 <- cbind(my_table_2, data_sample)
    +names(my_table_2) <- names(Hamilton_table_2)
    +

    Finally, rbind Hamilton’s table 2 with my table for a visual comparison. The results are nearly identical, inspiring confidence in the replication of the approach, as the functions of the neverhpfilter package.

    +

    According to the ‘code and data’ link on the ‘Current Working Papers’ page of Hamilton’s site, both Matlab and RATS were used for computation of the table. It is not surprising that minor differences in estimates would occur, likely due to differences in the underlying data or internal computational choices made by each commercial software product. While economic time series are publicly available and have a central source at FRED, that is not so for Standard & Poor’s index data. Unsurprisingly, the SP500 data shows the most divergence, and it is not clear what source was used in the original paper (though I have my suspicions for future exploration).

    +

    Below, see Hamilton’s table 2 compared with estimates from neverhpfilter::yth_filter, sorted by standard deviation of the cycle component. yth_filter estimates are labeled with the suffix .cycle

    +
     # Combined table
    +combined_table <- rbind(Hamilton_table_2[-NROW(Hamilton_table_2),], my_table_2)
    +
    +combined_table[order(combined_table$cycle.sd),]
    +
    ##                        cycle.sd gdp.cor random.sd gdp.rand.cor          Sample
    +## Unemployment-rate          1.44   -0.81      1.72        -0.79   1948-1/2016-2
    +## UNRATENSA.cycle            1.44   -0.82      1.71        -0.80 1948-Q1/2016-Q2
    +## 10-year-Treasury-yield     1.46   -0.05      1.51         0.08   1953-2/2016-2
    +## GS10.cycle                 1.46   -0.05      1.51         0.08 1953-Q2/2016-Q2
    +## Fedfunds-rate              2.78    0.33      3.03         0.40   1954-3/2016-2
    +## FEDFUNDS.cycle             2.78    0.33      3.03         0.41 1954-Q3/2016-Q2
    +## PCECC96.cycle              2.84    0.79      3.02         0.82 1947-Q1/2016-Q1
    +## Consumption                2.85    0.79      3.04         0.82   1947-1/2016-1
    +## GDP-Deflator               2.99    0.04      4.11        -0.13   1947-1/2016-1
    +## GDPDEF.cycle               3.00    0.03      4.12        -0.14 1947-Q1/2016-Q1
    +## Employment                 3.09    0.85      3.32         0.85   1947-1/2016-2
    +## PAYEMS.cycle               3.09    0.85      3.32         0.85 1947-Q1/2016-Q2
    +## GDPC1.cycle                3.37    1.00      3.65         1.00 1947-Q1/2016-Q1
    +## GDP                        3.38    1.00      3.69         1.00   1947-1/2016-1
    +## Government-spending        7.13    0.31      8.60         0.38   1947-1/2016-1
    +## GCEC1.cycle                7.16    0.31      8.59         0.38 1947-Q1/2016-Q1
    +## IMPGSC1.cycle              9.75    0.76      9.91         0.75 1947-Q1/2016-Q1
    +## Imports                    9.79    0.77      9.98         0.75   1947-1/2016-1
    +## EXPGSC1.cycle             10.75    0.33     11.32         0.30 1947-Q1/2016-Q1
    +## Exports                   10.77    0.33     11.33         0.30   1947-1/2016-1
    +## GPDIC1.cycle              13.14    0.83     13.65         0.78 1947-Q1/2016-Q1
    +## Investment                13.19    0.84     13.74         0.80   1947-1/2016-1
    +## SP500.cycle               21.38    0.42     21.60         0.40 1950-Q1/2016-Q2
    +## S&P500                    21.80    0.41     22.08         0.38   1950-1/2016-2

    Summary

    -

    The estimates generated with the neverhpfilter package are nearly identical to those displayed by Hamilton(2017). If one has the use case, the generalized functions will estimate higher frequency time series as well as error distributions other than Gaussian. In addition to consulting the paper which inspired this package, check out the documentation for yth_filter to learn more.

    +

    The estimates generated with the neverhpfilter package are nearly identical to those displayed by Hamilton (2017). If one has the use case, the generalized functions which inherit methods from glm and xts will estimate higher frequency time series as well as error distributions other than Gaussian. In addition to consulting the paper which inspired this package, check out the documentation for yth_filter to learn more, or reach out to me with any questions.

    diff --git a/docs/articles/index.html b/docs/articles/index.html index e5824a2..8beb6a3 100644 --- a/docs/articles/index.html +++ b/docs/articles/index.html @@ -67,7 +67,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/authors.html b/docs/authors.html index 68de2d0..b5a0629 100644 --- a/docs/authors.html +++ b/docs/authors.html @@ -67,7 +67,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/index.html b/docs/index.html index 55be741..e4b2dcb 100644 --- a/docs/index.html +++ b/docs/index.html @@ -33,7 +33,7 @@ neverhpfilter - 0.3.0 + 0.3.1 @@ -98,7 +98,7 @@

    Install from CRAN on R version >= 3.5.0.

    install.packages("neverhpfilter")

    Or install from the Github master branch on R version >= 3.5.0.

    -
    devtools::install_github("JustinMShea/neverhpfilter")
    +
    devtools::install_github("JustinMShea/neverhpfilter")

    Load the package

    library(neverhpfilter)
    diff --git a/docs/news/index.html b/docs/news/index.html index aefa734..2cc63b3 100644 --- a/docs/news/index.html +++ b/docs/news/index.html @@ -67,7 +67,7 @@ neverhpfilter - 0.3.0 + 0.3.1 @@ -120,13 +120,24 @@

    Changelog

    +
    +

    +neverhpfilter 0.3-1 Unreleased +

    +

    Content edits and cleanup of vignettes.

    +

    These included, removing the redundant call to library(xts) as it has been moved to Depends instead of merely Suggests, as documented in 0.3-0 below. Thus, calling neverhpfilter includes it.

    +

    While the vignette builder uses the knitr package, I was also loading the knitr package to access the kable function for tables. Testing was going fine, but then knitr inexplicably began throwing a variety of differing errors across Linux and Windows builds. This appears to be due to Suggested packages it couldn’t import, so removing calls to knitr in the vignette was an easy place to begin reducing the area of an unknown attack surface. In the modern era, regardless of the original error, any opportunity to reduce dependencies seems the most sensible approach as ever increasing dependency sprawl has bestowed upon R package maintainers a constant, exponentially growing, attack surface.

    +

    The decision to remove knitr::kable from vignettes was also an aesthetic one. In my experience, tables remain an important device for graphic displays of information. While knitr’s html format appears clean at first, closer inspection reveals the undesirable trait of fitting tables to full page width regardless of the number of columns to display. On deeper reflection, I view this as a bug, as it produces the undesirable side effect of too much white space for the reader’s eye to traverse when comparing numbers across columns.

    +

    Printing the raw output of an xts or data.frame objects keeps columns compact, allowing for clearer visual comparison. The raw output also better communicates to our reader the table was created as a result of some computational process. Plus, in an increasingly sophisticated digital world of Ux, these raw outputs look increasingly, unique, computationally cool, and clean. They serve as a reminder of the objective and scientific nature we strive for in our endeavors.

    +

    neverhpfilter 0.3-0 Unreleased

    Feature, updated data through January 2020.

    +

    New vignette Getting started reworks and replaces Additional examples.

    Increased R version dependency to (>= 3.5.0) for the .Rdata files.

    -

    Moved from testtthat to tinytest, and added addy function unit tests and data tests.

    +

    Moved from testtthat to tinytest, and wrote additional function unit tests and data unit tests.

    Moved xts and zoo from imports to depends. Now xts (>= 0.11-0) and zoo (>= 1.8-0)

    Bug fix, see issue-1 here.

    @@ -140,7 +151,7 @@

    neverhpfilter 0.2-0 2018-01-24

    -

    Consolidated into two functions. yth_glm remains unchanged, while yth_filter has been given an output argument to specify the return of specific series. This feature eliminates the need for yth_cycle and yth_trend, which were helpful when applying the function to multiple data sets. Done so at the strong suggestion of CRAN.

    +

    Consolidated into two functions. yth_glm remains unchanged, while yth_filter has been given an output argument to specify the return of specific series. This feature eliminates the need for yth_cycle and yth_trend, which were helpful when applying the function to multiple data sets. Done so at the strong suggestion of CRAN, and has ultimatly proven a good idea.

    Additional data sets have been added to replicate most all of Hamilton’s table 2.

    The “Reproducing Hamilton” vignette has been expanded and content has been edited for clarity.

    @@ -156,6 +167,7 @@

    Contents

    diff --git a/docs/reference/FEDFUNDS.html b/docs/reference/FEDFUNDS.html index bbf43ed..5732aaa 100644 --- a/docs/reference/FEDFUNDS.html +++ b/docs/reference/FEDFUNDS.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/GCEC1.html b/docs/reference/GCEC1.html index 759e9f5..9d9ebc4 100644 --- a/docs/reference/GCEC1.html +++ b/docs/reference/GCEC1.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/GDPC1.html b/docs/reference/GDPC1.html index 44716d3..cb40730 100644 --- a/docs/reference/GDPC1.html +++ b/docs/reference/GDPC1.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/GDPDEF.html b/docs/reference/GDPDEF.html index b579f93..2e1f3ae 100644 --- a/docs/reference/GDPDEF.html +++ b/docs/reference/GDPDEF.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/GPDIC1.html b/docs/reference/GPDIC1.html index 49758be..b6ef3bf 100644 --- a/docs/reference/GPDIC1.html +++ b/docs/reference/GPDIC1.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/GS10.html b/docs/reference/GS10.html index 6588bb2..a164578 100644 --- a/docs/reference/GS10.html +++ b/docs/reference/GS10.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/Hamilton_table_2.html b/docs/reference/Hamilton_table_2.html index a795e82..05545b6 100644 --- a/docs/reference/Hamilton_table_2.html +++ b/docs/reference/Hamilton_table_2.html @@ -70,7 +70,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/IMPGSC1.html b/docs/reference/IMPGSC1.html index 75282ae..cd3252b 100644 --- a/docs/reference/IMPGSC1.html +++ b/docs/reference/IMPGSC1.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/PAYEMS.html b/docs/reference/PAYEMS.html index 8b42434..f8631e7 100644 --- a/docs/reference/PAYEMS.html +++ b/docs/reference/PAYEMS.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/PCECC96.html b/docs/reference/PCECC96.html index f98b66a..239de7e 100644 --- a/docs/reference/PCECC96.html +++ b/docs/reference/PCECC96.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/SP500.html b/docs/reference/SP500.html index 47cad0a..04fa617 100644 --- a/docs/reference/SP500.html +++ b/docs/reference/SP500.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/UNRATENSA.html b/docs/reference/UNRATENSA.html index 4d9b777..b7501fb 100644 --- a/docs/reference/UNRATENSA.html +++ b/docs/reference/UNRATENSA.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/USREC.html b/docs/reference/USREC.html index 282fb11..a1e6e73 100644 --- a/docs/reference/USREC.html +++ b/docs/reference/USREC.html @@ -70,7 +70,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/index.html b/docs/reference/index.html index 905cabd..431ce0f 100644 --- a/docs/reference/index.html +++ b/docs/reference/index.html @@ -67,7 +67,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/yth_filter.html b/docs/reference/yth_filter.html index 47b4885..bf6d766 100644 --- a/docs/reference/yth_filter.html +++ b/docs/reference/yth_filter.html @@ -70,7 +70,7 @@ neverhpfilter - 0.3.0 + 0.3.1 diff --git a/docs/reference/yth_glm.html b/docs/reference/yth_glm.html index 3df79b8..11943db 100644 --- a/docs/reference/yth_glm.html +++ b/docs/reference/yth_glm.html @@ -69,7 +69,7 @@ neverhpfilter - 0.3.0 + 0.3.1