Skip to content

Commit 547f486

Browse files
committed
add jvn vignette
1 parent 748d33b commit 547f486

6 files changed

Lines changed: 382 additions & 8 deletions

File tree

R/jvn.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ jvn_nowcast <- function(df,
161161
"Filter to a single ID first."
162162
))
163163
}
164-
df <- vintages_wide(df, names_from = "release")
164+
df <- suppressWarnings(vintages_wide(df, names_from = "release"))
165165
# Handle if vintages_wide returns a list
166166
if (is.list(df) && !is.data.frame(df)) df <- df[[1]]
167167
}

R/kk.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ kk_nowcast <- function(
256256
"Filter to a single ID first."
257257
))
258258
}
259-
df <- vintages_wide(df, names_from = "release")
259+
df <- suppressWarnings(vintages_wide(df, names_from = "release"))
260260
# Handle if vintages_wide returns a list
261261
if (is.list(df) && !is.data.frame(df)) df <- df[[1]]
262262
}

_pkgdown.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ articles:
5353
- understanding-revisions
5454
- revision-analysis
5555
- efficient-release
56-
- nowcasting-revisions
56+
- nowcasting-revisions-kk
57+
- nowcasting-revisions-jvn
5758

5859
- title: "Why revisions matter"
5960
contents:
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
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

Comments
 (0)