--- title: "Tracking core inflation revisions" author: "Charles Coverdale" date: "`r format(Sys.Date(), '%d %B %Y')`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Tracking core inflation revisions} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} library(fred) key_available <- nzchar(Sys.getenv("FRED_API_KEY")) knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 7, fig.height = 4.5, eval = key_available ) ``` CPI revisions look small in absolute terms but matter materially for inflation-targeting central banks. The Federal Reserve targets PCE; markets focus on CPI; the BLS revises seasonal factors annually. A nowcast or policy narrative built on revised numbers can look very different from the same narrative built on the data that was actually available at the time. This vignette uses `fred_real_time_panel()` to track how core inflation estimates have evolved across vintages, and `fred_vintage_revisions()` to quantify the revision behaviour of headline series. The chunks below require an API key. ## Setup ```{r} library(fred) ``` ## Headline vs core, revised The simple comparison most analysts start with: headline CPI vs core CPI (food and energy excluded), as we see them today. ```{r} inflation_now <- fred_series( c("CPIAUCSL", "CPILFESL"), from = "2018-01-01", transform = "yoy_pct", format = "wide" ) plot(inflation_now, ylab = "% YoY", main = "Headline vs core CPI, latest vintage") ``` This is what shows up in most papers. But the *actual story* policymakers saw at each FOMC meeting is closer to the first-release values. ## First-release inflation Use `fred_first_release()` to get the value that was published at each release date, with no subsequent revisions: ```{r} core_first <- fred_first_release( "CPILFESL", from = "2018-01-01", units = "pc1" # YoY percent change ) core_latest <- fred_series( "CPILFESL", from = "2018-01-01", transform = "yoy_pct" ) # Plot both on one chart plot(core_first$date, core_first$value, type = "l", xlab = "", ylab = "% YoY", main = "Core CPI: first release vs latest vintage", ylim = range(c(core_first$value, core_latest$value), na.rm = TRUE)) graphics::lines(core_latest$date, core_latest$value, col = "tomato") graphics::legend("topleft", legend = c("First release", "Latest vintage"), col = c("black", "tomato"), lty = 1, bty = "n") ``` The two lines diverge meaningfully across pivot points (early 2022, late 2023). That divergence is the data revision. ## Real-time panel at FOMC vintages Pull a panel of core CPI as it was seen on each FOMC SEP meeting in 2024. This is the data that informed Summary of Economic Projections forecasts. ```{r} sep_meetings <- fred_fomc_dates(year = 2024, sep_only = TRUE) sep_meetings ``` ```{r} panel <- fred_real_time_panel( "CPILFESL", vintages = sep_meetings$date, from = "2022-01-01" ) head(panel) ``` The `realtime_start` column tells you which vintage each row belongs to. To visualise the four lines: ```{r} panel_wide <- stats::reshape( panel[, c("date", "value", "realtime_start")], idvar = "date", timevar = "realtime_start", direction = "wide" ) names(panel_wide) <- sub("^value\\.", "v", names(panel_wide)) panel_wide <- panel_wide[order(panel_wide$date), ] cols <- c("#1F77B4", "#FF7F0E", "#2CA02C", "#D62728") plot(panel_wide$date, panel_wide[[2]], type = "l", col = cols[1], ylim = range(unlist(panel_wide[, -1]), na.rm = TRUE), xlab = "", ylab = "Core CPI level", main = "Core CPI as seen at four 2024 SEP meetings") for (i in 3:ncol(panel_wide)) { graphics::lines(panel_wide$date, panel_wide[[i]], col = cols[i - 1L]) } graphics::legend("topleft", legend = format(sep_meetings$date, "%b %Y"), col = cols, lty = 1, bty = "n", cex = 0.8) ``` The vintage panel makes it visually obvious where revisions accumulated. ## Quantifying revisions For a research-grade summary, use `fred_vintage_revisions()`: ```{r} rev <- fred_vintage_revisions("CPILFESL", from = "2020-01-01") head(rev) summary(rev$revision_total_pct) ``` The output gives, per observation date: how many vintages exist, the first and final value, total revision (in level and percent), mean and SD of inter-vintage revisions, and elapsed days from first publication to final. Use it to: * Pick low-revision series for nowcasting (small `revision_sd`). * Identify observation periods where revisions are unusually large (typically structural-break or seasonal-factor years). ## Reproducibility Pin the vintage in your citation, so a reviewer in 2027 sees the same data: ```{r, eval = TRUE} fred_cite_series( "CPILFESL", vintage_date = "2024-12-18", format = "bibtex" ) ``` ## Further reading * `vignette("nowcasting-with-fred")` for using vintages in a nowcasting backtest. * `vignette("multi-series-workflows")` for the basic fetch/transform/plot pattern.