|
| 1 | +--- |
| 2 | +title: "Nowcasting revisions using the Jacobs-Van Norden model" |
| 3 | +output: rmarkdown::html_vignette |
| 4 | +bibliography: references.bib |
| 5 | +biblio-style: apalike |
| 6 | +link-citations: true |
| 7 | +vignette: > |
| 8 | + %\VignetteIndexEntry{nowcasting-revisions-jvn} |
| 9 | + %\VignetteEngine{knitr::rmarkdown} |
| 10 | + %\VignetteEncoding{UTF-8} |
| 11 | +--- |
| 12 | + |
| 13 | +```{r, include = FALSE} |
| 14 | +knitr::opts_chunk$set( |
| 15 | + collapse = TRUE, |
| 16 | + comment = "#>" |
| 17 | +) |
| 18 | +``` |
| 19 | + |
| 20 | +Having established that revisions are predictable, we can now apply nowcasting techniques to estimate the current state of the economy. This vignette demonstrates how to implement a nowcasting model using the Jacobs-Van Norden (JVN) framework (@jacobsModelingDataRevisions2011). |
| 21 | + |
| 22 | +## The Jacobs-van Norden Model |
| 23 | + |
| 24 | +The JVN model provides a flexible state-space framework for decomposing data revisions into economically meaningful components: **news** and **noise**. Unlike traditional approaches that treat all revisions as either pure information updates or pure measurement error, the JVN model allows for a mixture of both, providing a more realistic representation of the revision process. |
| 25 | + |
| 26 | +### Key Features |
| 27 | + |
| 28 | +- **News component** ($\nu_t$): Represents genuine new information about the true state of the economy that was not available at the time of the initial release |
| 29 | +- **Noise component** ($\zeta_t$): Represents measurement error or temporary distortions in preliminary estimates that are corrected in subsequent revisions |
| 30 | +- **Spillover effects**: Allow revisions to one vintage to affect revisions to other vintages, capturing the complex dynamics of the revision process |
| 31 | +- **Flexible dynamics**: Accommodates autoregressive behavior in the true underlying series |
| 32 | + |
| 33 | +### Model Structure |
| 34 | + |
| 35 | +The JVN model is represented in state-space form (notation following @durbinTimeSeriesAnalysis2012) with two key equations: |
| 36 | + |
| 37 | +**1. The Observation Equation** |
| 38 | + |
| 39 | +The observation equation links the observed data vintages to the latent state variables: |
| 40 | + |
| 41 | +$$ |
| 42 | +y_t = Z \alpha_t |
| 43 | +$$ |
| 44 | + |
| 45 | +where $y_t$ contains the different vintages of data available at time $t$, and $\alpha_t$ is the state vector containing the true value, news, and noise components. |
| 46 | + |
| 47 | +**2. The State Equation** |
| 48 | + |
| 49 | +The state equation describes the dynamics of the latent states: |
| 50 | + |
| 51 | +$$ |
| 52 | +\alpha_{t+1} = T \alpha_t + R \eta_t |
| 53 | +$$ |
| 54 | + |
| 55 | +where $\eta_t \sim N(0, Q)$ represents the structural shocks. |
| 56 | + |
| 57 | +### Example: AR(2) Model with Three Releases |
| 58 | + |
| 59 | +Consider an AR(2) process for the true output growth with three data releases. The complete model can be written as: |
| 60 | + |
| 61 | +$$ |
| 62 | +\begin{bmatrix} |
| 63 | +y_{t}^{t+1} \\ |
| 64 | +y_{t}^{t+2} \\ |
| 65 | +y_{t}^{t+3} |
| 66 | +\end{bmatrix} |
| 67 | += |
| 68 | +\begin{bmatrix} |
| 69 | +1 & 0 & 1 & 0 & 0 & 1 & 0 & 0 \\ |
| 70 | +1 & 0 & 0 & 1 & 0 & 0 & 1 & 0 \\ |
| 71 | +1 & 0 & 0 & 0 & 1 & 0 & 0 & 1 |
| 72 | +\end{bmatrix} |
| 73 | +\begin{bmatrix} |
| 74 | +\tilde{y}_{t} \\ |
| 75 | +\tilde{y}_{t-1} \\ |
| 76 | +\nu_{1t} \\ |
| 77 | +\nu_{2t} \\ |
| 78 | +\nu_{3t} \\ |
| 79 | +\zeta_{1t} \\ |
| 80 | +\zeta_{2t} \\ |
| 81 | +\zeta_{3t} |
| 82 | +\end{bmatrix} |
| 83 | +$$ |
| 84 | + |
| 85 | +The state vector evolves according to: |
| 86 | + |
| 87 | +$$ |
| 88 | +\begin{bmatrix} |
| 89 | +\tilde{y}_{t} \\ |
| 90 | +\tilde{y}_{t-1} \\ |
| 91 | +\nu_{1t} \\ |
| 92 | +\nu_{2t} \\ |
| 93 | +\nu_{3t} \\ |
| 94 | +\zeta_{1t} \\ |
| 95 | +\zeta_{2t} \\ |
| 96 | +\zeta_{3t} |
| 97 | +\end{bmatrix} |
| 98 | += |
| 99 | +\begin{bmatrix} |
| 100 | +\rho_1 & \rho_2 & 0 & 0 & 0 & 0 & 0 & 0 \\ |
| 101 | +1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ |
| 102 | +0 & 0 & \tau_{\nu 1} & 0 & 0 & 0 & 0 & 0 \\ |
| 103 | +0 & 0 & 0 & \tau_{\nu 2} & 0 & 0 & 0 & 0 \\ |
| 104 | +0 & 0 & 0 & 0 & \tau_{\nu 3} & 0 & 0 & 0 \\ |
| 105 | +0 & 0 & 0 & 0 & 0 & \tau_{\zeta 1} & 0 & 0 \\ |
| 106 | +0 & 0 & 0 & 0 & 0 & 0 & \tau_{\zeta 2} & 0 \\ |
| 107 | +0 & 0 & 0 & 0 & 0 & 0 & 0 & \tau_{\zeta 3} |
| 108 | +\end{bmatrix} |
| 109 | +\begin{bmatrix} |
| 110 | +\tilde{y}_{t-1} \\ |
| 111 | +\tilde{y}_{t-2} \\ |
| 112 | +\nu_{1,t-1} \\ |
| 113 | +\nu_{2,t-1} \\ |
| 114 | +\nu_{3,t-1} \\ |
| 115 | +\zeta_{1,t-1} \\ |
| 116 | +\zeta_{2,t-1} \\ |
| 117 | +\zeta_{3,t-1} |
| 118 | +\end{bmatrix} |
| 119 | ++ \\ |
| 120 | +\begin{bmatrix} |
| 121 | +\sigma _{e} & \sigma _{\nu 1} & \sigma _{\nu 2} & \sigma _{\nu 3} & 0 & 0 & 0 \\ |
| 122 | +0 & 0 & 0 & 0 & 0 & 0 & 0 \\ |
| 123 | +0 & -\sigma _{\nu 1} & -\sigma _{\nu 2} & -\sigma _{\nu 3} & 0 & 0 & 0 \\ |
| 124 | +0 & 0 & -\sigma _{\nu 2} & -\sigma _{\nu 3} & 0 & 0 & 0 \\ |
| 125 | +0 & 0 & 0 & -\sigma _{\nu 3} & 0 & 0 & 0 \\ |
| 126 | +0 & 0 & 0 & 0 & 0 & \sigma _{\zeta 1} & 0 & 0 \\ |
| 127 | +0 & 0 & 0 & 0 & 0 & 0 & \sigma _{\zeta 2} & 0 \\ |
| 128 | +0 & 0 & 0 & 0 & 0 & 0 & 0 & \sigma _{\zeta 3} \\ |
| 129 | +\end{bmatrix} |
| 130 | +\cdot |
| 131 | +\begin{bmatrix} |
| 132 | +\eta _{et} \\ |
| 133 | +\eta _{\nu _{1}t} \\ |
| 134 | +\eta _{\nu _{2}t} \\ |
| 135 | +\eta _{\nu _{3}t} \\ |
| 136 | +\eta _{\zeta _{1}t} \\ |
| 137 | +\eta _{\zeta _{2}t} \\ |
| 138 | +\eta _{\zeta _{3}t} \\ |
| 139 | +\end{bmatrix} |
| 140 | +$$ |
| 141 | + |
| 142 | +The error loading matrix $R$ and shock vector $\eta_t$ capture how structural innovations affect each component. The true value $\tilde{y}_t$ is affected by all news shocks (cumulative information), while individual news and noise components receive their own independent shocks. |
| 143 | + |
| 144 | +### Parameters to Estimate |
| 145 | + |
| 146 | +For this example, the model has 15 free parameters: |
| 147 | + |
| 148 | +- **AR coefficients**: $\rho_1, \rho_2$ (dynamics of true value) |
| 149 | +- **Standard deviations**: $\sigma_e$ (AR shock), $\sigma_{\nu 1}, \sigma_{\nu 2}, \sigma_{\nu 3}$ (news), $\sigma_{\zeta 1}, \sigma_{\zeta 2}, \sigma_{\zeta 3}$ (noise) |
| 150 | +- **Spillover parameters**: $\tau_{\nu 1}, \tau_{\nu 2}, \tau_{\nu 3}$ (news persistence), $\tau_{\zeta 1}, \tau_{\zeta 2}, \tau_{\zeta 3}$ (noise persistence) |
| 151 | + |
| 152 | +### Nested Models |
| 153 | + |
| 154 | +The JVN framework is highly flexible and nests several special cases: |
| 155 | + |
| 156 | +- **News-only model**: Set $\sigma_{\zeta j} = 0$ for all $j$ (all revisions are information) |
| 157 | +- **Noise-only model**: Set $\sigma_{\nu j} = 0$ for all $j$ (all revisions are measurement error) |
| 158 | +- **No spillovers**: Set $\tau_{\nu j} = 0$ and $\tau_{\zeta j} = 0$ (revisions are i.i.d.) |
| 159 | + |
| 160 | +## Nowcasting with the JVN Model |
| 161 | + |
| 162 | +We demonstrate nowcasting Euro Area GDP using the JVN model. The procedure follows these steps: |
| 163 | + |
| 164 | +- Identify the efficient release (the first release that is not systematically revised) |
| 165 | +- Estimate the JVN model using Maximum Likelihood |
| 166 | +- Examine model fit and parameters |
| 167 | + |
| 168 | +### Identify Efficient Release |
| 169 | + |
| 170 | +```{r warning = FALSE, message=FALSE} |
| 171 | +library(reviser) |
| 172 | +library(dplyr) |
| 173 | +library(lubridate) |
| 174 | +library(ggplot2) |
| 175 | +
|
| 176 | +# Prepare GDP data |
| 177 | +gdp <- reviser::gdp %>% |
| 178 | + tsbox::ts_pc() %>% |
| 179 | + dplyr::filter( |
| 180 | + id == "EA", |
| 181 | + time >= min(pub_date), |
| 182 | + time <= as.Date("2020-01-01") |
| 183 | + ) %>% |
| 184 | + tidyr::drop_na() |
| 185 | +
|
| 186 | +# Get first 15 releases |
| 187 | +df <- get_nth_release(gdp, n = 0:14) |
| 188 | +
|
| 189 | +# Get final release (4 years after initial) |
| 190 | +final_release <- get_nth_release(gdp, n = 15) |
| 191 | +
|
| 192 | +# Test for efficient release |
| 193 | +efficient_release <- get_first_efficient_release( |
| 194 | + df, |
| 195 | + final_release |
| 196 | +) |
| 197 | +
|
| 198 | +data <- efficient_release$data |
| 199 | +e <- efficient_release$e |
| 200 | +
|
| 201 | +summary(efficient_release) |
| 202 | +``` |
| 203 | + |
| 204 | +The efficient release test identifies that $e = `r e`$, meaning the `r e+1`th release is an efficient estimate of the final value. |
| 205 | + |
| 206 | +### Estimate the JVN Model |
| 207 | + |
| 208 | +The `jvn_nowcast()` function estimates the model using Maximum Likelihood Estimation (MLE). You can specify: |
| 209 | + |
| 210 | +- **AR order**: The order of the autoregressive process for the true value |
| 211 | +- **Model components**: Whether to include news, noise, and/or spillovers |
| 212 | +- **Optimization method**: L-BFGS-B (default), two-step, nlminb, and more |
| 213 | +- **Standard error calculation**: Hessian-based (default) |
| 214 | + |
| 215 | +```{r warning = FALSE, message=FALSE} |
| 216 | +# Estimate JVN model with news and noise |
| 217 | +nowcast <- jvn_nowcast( |
| 218 | + df = data, |
| 219 | + e = e, |
| 220 | + ar_order = 1, |
| 221 | + h = 4, # 4-period ahead forecast |
| 222 | + include_news = TRUE, |
| 223 | + include_noise = TRUE, |
| 224 | + include_spillovers = FALSE, |
| 225 | + method = "L-BFGS-B" |
| 226 | +) |
| 227 | +
|
| 228 | +``` |
| 229 | + |
| 230 | +### Examine Model Fit and Parameter |
| 231 | + |
| 232 | +```{r warning = FALSE, message=FALSE} |
| 233 | +# Model diagnostics |
| 234 | +summary(nowcast) |
| 235 | +``` |
| 236 | + |
| 237 | +### Extract State Estimates |
| 238 | + |
| 239 | +The model provides both filtered and smoothed estimates: |
| 240 | + |
| 241 | +- **Filtered estimates**: Use only information available up to time $t$ |
| 242 | +- **Smoothed estimates**: Use the full sample (better for historical analysis) |
| 243 | + |
| 244 | +```{r warning = FALSE, message=FALSE} |
| 245 | +# Extract filtered states |
| 246 | +filtered_states <- nowcast$states %>% |
| 247 | + filter(filter == "filtered", state == "true_lag_0") |
| 248 | +
|
| 249 | +# View recent estimates |
| 250 | +tail(filtered_states, 8) |
| 251 | +``` |
| 252 | + |
| 253 | +### Visualize Results |
| 254 | + |
| 255 | +```{r warning = FALSE, message=FALSE} |
| 256 | +plot(nowcast) |
| 257 | +
|
| 258 | +# Compare news and noise components |
| 259 | +nowcast$states %>% |
| 260 | + filter(filter == "smoothed", grepl("news|noise", state)) %>% |
| 261 | + ggplot(aes(x = time, y = estimate, color = state)) + |
| 262 | + geom_line() + |
| 263 | + labs( |
| 264 | + title = "News and Noise Components", |
| 265 | + x = "Time", |
| 266 | + y = "Contribution" |
| 267 | + ) + |
| 268 | + theme_minimal() |
| 269 | +``` |
| 270 | + |
| 271 | +## Advanced Features |
| 272 | + |
| 273 | +### Multi-Start Optimization |
| 274 | + |
| 275 | +For complex models, it's recommended to use multi-start optimization to avoid local optima: |
| 276 | + |
| 277 | +```{r warning = FALSE, message=FALSE, eval=FALSE} |
| 278 | +nowcast_robust <- jvn_nowcast( |
| 279 | + df = data, |
| 280 | + e = e, |
| 281 | + ar_order = 2, |
| 282 | + include_news = TRUE, |
| 283 | + include_noise = TRUE, |
| 284 | + include_spillovers = TRUE, |
| 285 | + solver_options = list( |
| 286 | + n_starts = 5, # Try 5 different starting points |
| 287 | + trace = 1, # Show progress |
| 288 | + maxiter = 2000 # Increase max iterations |
| 289 | + ) |
| 290 | +) |
| 291 | +``` |
| 292 | + |
| 293 | +### Model Comparison |
| 294 | + |
| 295 | +Compare different specifications to find the best fit: |
| 296 | + |
| 297 | +```{r warning = FALSE, message=FALSE, eval=FALSE} |
| 298 | +# News-only model |
| 299 | +model_news <- jvn_nowcast(data, e, include_news = TRUE, include_noise = FALSE) |
| 300 | +
|
| 301 | +# Noise-only model |
| 302 | +model_noise <- jvn_nowcast(data, e, include_news = FALSE, include_noise = TRUE) |
| 303 | +
|
| 304 | +# Full model with spillovers |
| 305 | +model_full <- jvn_nowcast( |
| 306 | + data, e, |
| 307 | + include_news = TRUE, |
| 308 | + include_noise = TRUE, |
| 309 | + include_spillovers = TRUE |
| 310 | +) |
| 311 | +
|
| 312 | +# Compare BIC (lower is better) |
| 313 | +data.frame( |
| 314 | + Model = c("News Only", "Noise Only", "Full with Spillovers"), |
| 315 | + BIC = c(model_news$bic, model_noise$bic, model_full$bic), |
| 316 | + AIC = c(model_news$aic, model_noise$aic, model_full$aic) |
| 317 | +) |
| 318 | +``` |
| 319 | + |
| 320 | +### Custom Starting Values |
| 321 | + |
| 322 | +For difficult optimization problems, you can provide custom starting values: |
| 323 | + |
| 324 | +```{r warning = FALSE, message=FALSE, eval=FALSE} |
| 325 | +# Get the number of parameters |
| 326 | +n_params <- nowcast$jvn_model_mat$param_info$n_params |
| 327 | +
|
| 328 | +# Provide custom starting values |
| 329 | +custom_starts <- rep(0.1, n_params) |
| 330 | +
|
| 331 | +nowcast_custom <- jvn_nowcast( |
| 332 | + df = data, |
| 333 | + e = e, |
| 334 | + solver_options = list( |
| 335 | + startvals = custom_starts, |
| 336 | + transform_se = TRUE |
| 337 | + ) |
| 338 | +) |
| 339 | +``` |
| 340 | + |
| 341 | +## Interpretation |
| 342 | + |
| 343 | +### News vs Noise |
| 344 | + |
| 345 | +The key insight from the JVN model is the decomposition of revisions: |
| 346 | + |
| 347 | +- **Large news variances** ($\sigma_{\nu j}$): Initial releases understate the true value; revisions contain important information |
| 348 | +- **Large noise variances** ($\sigma_{\zeta j}$): Initial releases are noisy; revisions mainly remove measurement error |
| 349 | +- **AR dynamics** ($\rho_1, \rho_2$): Persistence in the true underlying series |
| 350 | + |
| 351 | +### Forecasting Implications |
| 352 | + |
| 353 | +- If revisions are mainly **news**: Initial releases should be given less weight; wait for revisions |
| 354 | +- If revisions are mainly **noise**: Initial releases already contain most information; revisions are less informative |
| 355 | +- **Spillovers** indicate that information in one revision affects expectations about other revisions |
| 356 | + |
| 357 | +## References |
0 commit comments