Bootstrapping Diffusion Indices

Author

AE Rodriguez

Ok, so unemployment improved in March 2026 from 4.4 to 4.3; a change of -0.1. What we all want to know if the change is large enough to be a “real” or is it merely sampling variance. Is the economy shifting or is it just noise?

A monthly improvement in the U.S. unemployment rate is often not statistically significant due to sampling error, which generally requires a change of about 0.2 percentage points or more (90% confidence) to be considered meaningful; small fluctuations (e.g., 0.1) are frequently within the margin of error.

The agency calculates the standard error for the survey. But what if we weren’t aware of the sampling error.

Bootstrapping provides a practical method to calculate standard errors and confidence intervals without relying on strict assumptions about the underlying change-in-unemployment distribution. This enables us to determine whether a monthly change is statistically significant.

suppressWarnings({
  suppressPackageStartupMessages({
library(tidyverse)
library(boot)
#devtools::install_github("keberwein/blscrapeR")
# https://github.com/keberwein/blscrapeR
library(blscrapeR)
    library(pdfetch)
    library(TSstudio)
})
})

Bootstrapping is a statistical resampling technique that estimates the sampling distribution of a statistic (like mean or variance) by repeatedly drawing samples with replacement from a single original dataset.

Bootstrapping works because it treats the sample as the population. This process of resampling generates thousands of sample which allows for the creation of an empirical sampling distribution and the calculation of confidence intervals.

Data is from FRED. Here we download it and shorten it a bit - for aesthetics.

unemp_rate = pdfetch_FRED("UNRATE")
unemp_rate = ts(unemp_rate, start = c(1948,1),freq = 12 )
unemp_rate = window(unemp_rate, start = c(2015,1),
                    end = c(2026,3))
unemp_rate <- zoo::na.approx(unemp_rate)
TSstudio::ts_plot(unemp_rate, title = "Unemployment Rate")

Define the statistic to bootstrap (e.g., the mean of the change in the monthly unemployment rate).

unemp_change = diff(unemp_rate,1)
get_mean <- function(x) { mean(x) }

Calculate Statistical Significance (Confidence Intervals)

boot.ci helps determine if a value is significant (e.g., if CI excludes 0)

The package uses a block boostrap - which is necessary for correlated data like the unemployment change time series. It keeps blocks of data together to preserve structure.

set.seed(42) # For reproducibility
boot_results <- tsboot(tseries = unemp_change, 
                       statistic = get_mean, 
                       R = 1000, 
                       l = 12, 
                       sim = "fixed")


boot_ci <- boot.ci(boot_results, type = "perc")

boot_ci
BOOTSTRAP CONFIDENCE INTERVAL CALCULATIONS
Based on 1000 bootstrap replicates

CALL : 
boot.ci(boot.out = boot_results, type = "perc")

Intervals : 
Level     Percentile     
95%   (-0.1112,  0.1164 )  
Calculations and Intervals on Original Scale
plot.ts(unemp_change, type = "l", 
        ylim = c(-2,2),
        ylab = "Change, month-to-month",
        xlab = "Year",
        main = "Unemployment Change")
abline(h=0, lty = 2)
segments(x0 = 2022, x1 = 2026, 
         y0 = boot_ci[[4]][5], y1 = boot_ci[[4]][5], 
         lty = 2, col = "darkred") #
segments(x0 = 2022, x1 = 2026, 
         y0 = boot_ci[[4]][4], y1 = boot_ci[[4]][4], 
         lty = 2, col = "darkred") #

unemp_change = window(unemp_change, start = c(2022,1),
                    end = c(2026,3))

plot.ts(unemp_change, type = "l",
         ylim = c(-0.25,0.25),
        ylab = "Change, month-to-month",
        xlab = "Year",
        main = "Unemployment Change")
  abline(h=0, lty = 2)
segments(x0 = 2022, x1 = 2026, 
         y0 = boot_ci[[4]][4], y1 = boot_ci[[4]][4], 
         lty = 2, col = "darkred") #
segments(x0 = 2022, x1 = 2026, 
         y0 = boot_ci[[4]][5], y1 = boot_ci[[4]][5], 
         lty = 2, col = "darkred") #

The official Current Population Survey (CPS) typically considers a month-to-month change of roughly 0.2 percentage points or a three-month cumulative change of 0.3 percentage points as significant at the 90% confidence level.

The following plot identifies the bootstrap confidence interval and the CPS error estimates. Note that the bootstrap measures are systematically smaller than the agency survey error estimates.

plot.ts(unemp_change, 
        type = "l",
        ylim = c(-0.25,0.25),
        ylab = "Change, month-to-month",
        xlab = "Year",
        main = "Unemployment Change")
abline(h=0, lty = 2)
segments(x0 = 2022, x1 = 2026, 
         y0 = boot_ci[[4]][4], y1 = boot_ci[[4]][4], 
         lty = 2, col = "darkred") #
segments(x0 = 2022, x1 = 2026, 
         y0 = boot_ci[[4]][5], y1 = boot_ci[[4]][5], 
         lty = 2, col = "darkred") #

segments(x0 = 2022, x1 = 2026, 
         y0 = 0.2, y1 = 0.2, 
         lty = 2, col = "darkblue") #
segments(x0 = 2022, x1 = 2026, 
         y0 = -0.2, y1 = -0.2, 
         lty = 2, col = "darkblue") #