Skip to content
statsmodels logo
statsmodels 0.14.0 (+479) Trends and cycles in unemployment
Type to start searching
    statsmodels
    • Examples
    statsmodels
    • Installing statsmodels
    • Getting started
    • User Guide
    • Examples
      • Linear Regression Models
      • Plotting
      • Discrete Choice Models
      • Nonparametric Statistics
      • Generalized Linear Models
      • Robust Regression
      • Generalized Estimating Equations
      • Statistics
      • Time Series Analysis
      • State space models
        • SARIMAX and ARIMA: Frequently Asked Questions (FAQ)
        • VARMAX models
        • Dynamic factors and coincident indices
        • Detrending, Stylized Facts and the Business Cycle
        • Trends and cycles in unemployment
          • Trends and cycles in unemployment
            • Hodrick-Prescott (HP) filter
            • Unobserved components and ARIMA model (UC-ARIMA)
            • Unobserved components with stochastic cycle (UC)
            • Graphical comparison
          • Show Source
        • State space modeling: Local Linear Trends
        • Autoregressive Moving Average (ARMA): Sunspots data
        • Seasonality in time series data
        • Estimating or specifying parameters in state space models
        • TVP-VAR, MCMC, and sparse simulation smoothing
        • Fast Bayesian estimation of SARIMAX models
        • Forecasting, updating datasets, and the “news”
        • Custom statespace models
        • ETS models
      • State space models - Technical notes
      • Forecasting
      • Multivariate Methods
      • User Notes
    • API Reference
    • About statsmodels
    • Developer Page
    • Release Notes
    • Trends and cycles in unemployment
      • Hodrick-Prescott (HP) filter
      • Unobserved components and ARIMA model (UC-ARIMA)
      • Unobserved components with stochastic cycle (UC)
      • Graphical comparison
    • Show Source

    Trends and cycles in unemployment¶

    Here we consider three methods for separating a trend and cycle in economic data. Supposing we have a time series \(y_t\), the basic idea is to decompose it into these two components:

    \[y_t = \mu_t + \eta_t\]

    where \(\mu_t\) represents the trend or level and \(\eta_t\) represents the cyclical component. In this case, we consider a stochastic trend, so that \(\mu_t\) is a random variable and not a deterministic function of time. Two of methods fall under the heading of “unobserved components” models, and the third is the popular Hodrick-Prescott (HP) filter. Consistent with e.g. Harvey and Jaeger (1993), we find that these models all produce similar decompositions.

    This notebook demonstrates applying these models to separate trend from cycle in the U.S. unemployment rate.

    [1]:
    
    %matplotlib inline
    
    [2]:
    
    import numpy as np
    import pandas as pd
    import statsmodels.api as sm
    import matplotlib.pyplot as plt
    
    [3]:
    
    from pandas_datareader.data import DataReader
    endog = DataReader('UNRATE', 'fred', start='1954-01-01')
    endog.index.freq = endog.index.inferred_freq
    

    Hodrick-Prescott (HP) filter¶

    The first method is the Hodrick-Prescott filter, which can be applied to a data series in a very straightforward method. Here we specify the parameter \(\lambda=129600\) because the unemployment rate is observed monthly.

    [4]:
    
    hp_cycle, hp_trend = sm.tsa.filters.hpfilter(endog, lamb=129600)
    

    Unobserved components and ARIMA model (UC-ARIMA)¶

    The next method is an unobserved components model, where the trend is modeled as a random walk and the cycle is modeled with an ARIMA model - in particular, here we use an AR(4) model. The process for the time series can be written as:

    \[\begin{split}\begin{align} y_t & = \mu_t + \eta_t \\ \mu_{t+1} & = \mu_t + \epsilon_{t+1} \\ \phi(L) \eta_t & = \nu_t \end{align}\end{split}\]

    where \(\phi(L)\) is the AR(4) lag polynomial and \(\epsilon_t\) and \(\nu_t\) are white noise.

    [5]:
    
    mod_ucarima = sm.tsa.UnobservedComponents(endog, 'rwalk', autoregressive=4)
    # Here the powell method is used, since it achieves a
    # higher loglikelihood than the default L-BFGS method
    res_ucarima = mod_ucarima.fit(method='powell', disp=False)
    print(res_ucarima.summary())
    
                            Unobserved Components Results
    ==============================================================================
    Dep. Variable:                 UNRATE   No. Observations:                  821
    Model:                    random walk   Log Likelihood                -457.661
                                  + AR(4)   AIC                            927.321
    Date:                Wed, 22 Jun 2022   BIC                            955.577
    Time:                        04:40:04   HQIC                           938.163
    Sample:                    01-01-1954
                             - 05-01-2022
    Covariance Type:                  opg
    ================================================================================
                       coef    std err          z      P>|z|      [0.025      0.975]
    --------------------------------------------------------------------------------
    sigma2.level     0.0756      0.165      0.458      0.647      -0.248       0.399
    sigma2.ar        0.1014      0.167      0.606      0.545      -0.227       0.429
    ar.L1            1.0619      0.106     10.006      0.000       0.854       1.270
    ar.L2           -0.1759      0.303     -0.581      0.561      -0.769       0.417
    ar.L3            0.0897      0.185      0.486      0.627      -0.272       0.451
    ar.L4           -0.0216      0.078     -0.278      0.781      -0.174       0.131
    ===================================================================================
    Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):           6028026.69
    Prob(Q):                              0.95   Prob(JB):                         0.00
    Heteroskedasticity (H):               9.36   Skew:                            17.11
    Prob(H) (two-sided):                  0.00   Kurtosis:                       421.64
    ===================================================================================
    
    Warnings:
    [1] Covariance matrix calculated using the outer product of gradients (complex-step).
    

    Unobserved components with stochastic cycle (UC)¶

    The final method is also an unobserved components model, but where the cycle is modeled explicitly.

    \[\begin{split}\begin{align} y_t & = \mu_t + \eta_t \\ \mu_{t+1} & = \mu_t + \epsilon_{t+1} \\ \eta_{t+1} & = \eta_t \cos \lambda_\eta + \eta_t^* \sin \lambda_\eta + \tilde \omega_t \qquad & \tilde \omega_t \sim N(0, \sigma_{\tilde \omega}^2) \\ \eta_{t+1}^* & = -\eta_t \sin \lambda_\eta + \eta_t^* \cos \lambda_\eta + \tilde \omega_t^* & \tilde \omega_t^* \sim N(0, \sigma_{\tilde \omega}^2) \end{align}\end{split}\]
    [6]:
    
    mod_uc = sm.tsa.UnobservedComponents(
        endog, 'rwalk',
        cycle=True, stochastic_cycle=True, damped_cycle=True,
    )
    # Here the powell method gets close to the optimum
    res_uc = mod_uc.fit(method='powell', disp=False)
    # but to get to the highest loglikelihood we do a
    # second round using the L-BFGS method.
    res_uc = mod_uc.fit(res_uc.params, disp=False)
    print(res_uc.summary())
    
                                Unobserved Components Results
    =====================================================================================
    Dep. Variable:                        UNRATE   No. Observations:                  821
    Model:                           random walk   Log Likelihood                -460.750
                       + damped stochastic cycle   AIC                            929.499
    Date:                       Wed, 22 Jun 2022   BIC                            948.327
    Time:                               04:40:05   HQIC                           936.724
    Sample:                           01-01-1954
                                    - 05-01-2022
    Covariance Type:                         opg
    ===================================================================================
                          coef    std err          z      P>|z|      [0.025      0.975]
    -----------------------------------------------------------------------------------
    sigma2.level        0.1806      0.004     42.655      0.000       0.172       0.189
    sigma2.cycle     1.599e-11      0.002    6.4e-09      1.000      -0.005       0.005
    frequency.cycle     0.3490    571.184      0.001      1.000   -1119.151    1119.849
    damping.cycle       0.1097     35.924      0.003      0.998     -70.299      70.519
    ===================================================================================
    Ljung-Box (L1) (Q):                   1.52   Jarque-Bera (JB):           6080363.13
    Prob(Q):                              0.22   Prob(JB):                         0.00
    Heteroskedasticity (H):               9.94   Skew:                            17.13
    Prob(H) (two-sided):                  0.00   Kurtosis:                       423.98
    ===================================================================================
    
    Warnings:
    [1] Covariance matrix calculated using the outer product of gradients (complex-step).
    

    Graphical comparison¶

    The output of each of these models is an estimate of the trend component \(\mu_t\) and an estimate of the cyclical component \(\eta_t\). Qualitatively the estimates of trend and cycle are very similar, although the trend component from the HP filter is somewhat more variable than those from the unobserved components models. This means that relatively mode of the movement in the unemployment rate is attributed to changes in the underlying trend rather than to temporary cyclical movements.

    [7]:
    
    fig, axes = plt.subplots(2, figsize=(13,5));
    axes[0].set(title='Level/trend component')
    axes[0].plot(endog.index, res_uc.level.smoothed, label='UC')
    axes[0].plot(endog.index, res_ucarima.level.smoothed, label='UC-ARIMA(2,0)')
    axes[0].plot(hp_trend, label='HP Filter')
    axes[0].legend(loc='upper left')
    axes[0].grid()
    
    axes[1].set(title='Cycle component')
    axes[1].plot(endog.index, res_uc.cycle.smoothed, label='UC')
    axes[1].plot(endog.index, res_ucarima.autoregressive.smoothed, label='UC-ARIMA(2,0)')
    axes[1].plot(hp_cycle, label='HP Filter')
    axes[1].legend(loc='upper left')
    axes[1].grid()
    
    fig.tight_layout();
    
    ../../../_images/examples_notebooks_generated_statespace_cycles_11_0.png
    Previous Detrending, Stylized Facts and the Business Cycle
    Next State space modeling: Local Linear Trends
    © Copyright 2009-2019, Josef Perktold, Skipper Seabold, Jonathan Taylor, statsmodels-developers.
    Last updated on Jun 22, 2022.
    Created using Sphinx 5.0.2. and Material for Sphinx