Exploring Economic Trends: A Comparison of U.S. Diffusion Index and CFNAIDIFF

Author

Satya Pramod Kalyanam

knitr::opts_chunk$set(echo = TRUE, warning = FALSE, message = FALSE)

Introduction

Understanding the dynamics of the U.S. economy requires both national and localized perspectives. This analysis constructs a diffusion index using employment, industrial production, and consumer sentiment and compares it to the Chicago Fed National Activity Diffusion Index (CFNAIDIFF). These insights help assess economic expansion and contraction over time.

Libraries and Data Loading

suppressWarnings({
  suppressPackageStartupMessages({
    library(tidyverse)
    library(quantmod)
    library(tsbox)
    library(zoo)
  })
})

options(digits = 3, scipen = 99999)
graphics.off()

Methodology

The diffusion index reflects economic expansion and contraction based on:

  1. Variables: Employment, industrial production, and consumer sentiment.

  2. Calculation:

    • Compute first differences of variables.

    • Assign signs to indicate positive (expansion), negative (contraction), or no change.

    • Aggregate results into the diffusion index: Index=Positive CountsTotal Counts−Negative CountsTotal Counts×100 = - 100Index=Total CountsPositive Counts​−Total CountsNegative Counts​×100

  3. Smoothing: A 7-month rolling average is applied for trend analysis.

Data Preparation

# Load economic variables
getSymbols(c("PAYEMS", "INDPRO", "UMCSENT"),
           src = "FRED", return.class = 'xts', 
           from = "2010-01-01", to = Sys.Date())
[1] "PAYEMS"  "INDPRO"  "UMCSENT"
# Data preprocessing
employment <- PAYEMS
industrial_production <- INDPRO
consumer_sentiment <- UMCSENT

employment_ss <- employment["2010-01-31/2024-09-01"] |> ts_ts()
industrial_ss <- industrial_production["2010-01-31/2024-09-01"] |> ts_ts()
sentiment_ss <- consumer_sentiment["2010-01-31/2024-09-01"] |> ts_ts()

mydata <- cbind.data.frame(employment_ss, industrial_ss, sentiment_ss)

mydf <- mydata %>%
  mutate(
    emp_diff = tsibble::difference(employment_ss, differences = 1),
    ind_diff = tsibble::difference(industrial_ss, differences = 1),
    sent_diff = tsibble::difference(sentiment_ss, differences = 1)
  ) %>%
  dplyr::select(emp_diff, ind_diff, sent_diff) %>%
  na.omit()

Visualization of Diffusion Index

# Construct diffusion index
mydf_mat <- apply(mydf, 2, sign)
pos <- apply(mydf_mat, 1, function(row) sum(row > 0))
neg <- apply(mydf_mat, 1, function(row) sum(row < 0))
tot <- pos + neg
index <- (pos / tot - neg / tot) * 100
ma_index <- rollmean(index, 7, align = "right", na.pad = TRUE)

Date <- seq.Date(from = as.Date("2010-05-01"), length.out = length(index), by = "month")
diffusion_df <- cbind.data.frame(Date, index, ma_index)

ggplot(diffusion_df, aes(x = Date, y = index)) +
  # Line for the diffusion index
  geom_line(color = "darkgreen", size = 0.8) +
  # Smoothed trend line with transparency
  geom_smooth(color = "blue", fill = "lightblue", alpha = 0.3, size = 1.2) +
  # Adding labels to key points
  geom_text(data = diffusion_df[c(1, nrow(diffusion_df)), ],
            aes(label = paste0(round(index, 2), "%")), 
            vjust = -1, size = 3.5, fontface = "bold", color = "darkred") +
  # Adding a horizontal reference line
  geom_hline(yintercept = 0, linetype = "dashed", color = "black", size = 0.8) +
  # Vertical line for a key event (e.g., COVID-19)
  geom_vline(xintercept = as.Date("2020-03-01"), linetype = "dotted", color = "red", size = 1) +
  annotate("text", x = as.Date("2020-03-01"), y = -90, 
           label = "COVID-19", color = "red", size = 4, hjust = 0, angle = 90) +
  # Title, subtitle, and axis labels
  labs(
    title = "U.S. Economic Diffusion Index Over Time",
    subtitle = "Analyzing economic trends with key highlights",
    x = "Year",
    y = "Diffusion Index (%)"
  ) +
  # Adjust y-axis limits to zoom out
  scale_y_continuous(limits = c(-120, 120)) +
  # Enhance visual appearance with themes
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(size = 20, face = "bold", hjust = 0.5, color = "darkblue"),
    plot.subtitle = element_text(size = 14, face = "italic", hjust = 0.5, color = "blue"),
    axis.title.x = element_text(size = 14, face = "bold", color = "black"),
    axis.title.y = element_text(size = 14, face = "bold", color = "black"),
    axis.text = element_text(size = 12, color = "black"),
    panel.grid.major = element_line(color = "gray85", size = 0.5),
    panel.grid.minor = element_blank(),
    legend.position = "none",
    plot.background = element_rect(fill = "white", color = "white")
  )

The chart represents the U.S. Economic Diffusion Index over time, highlighting fluctuations in economic conditions between 2010 and 2025. Below is a detailed analysis:

U.S. Economic Diffusion Index: 2010-2025

The U.S. Economic Diffusion Index reveals key economic trends and fluctuations over time:

  • 2010-2015: Moderate expansion with the index fluctuating around 50%, reflecting a stable economy.

  • 2015-2020: Gradual decline indicates growing economic softness in employment, production, and sentiment.

  • COVID-19 Impact (2020): A sharp dip highlights severe contraction due to lockdowns and disruptions.

  • 2020-2025: Partial recovery post-pandemic, but the index stabilizes below pre-2020 levels, reaching 33.83% by 2025, signaling weaker expansion.

Trend Highlights:

  • The blue smoothed line shows a long-term declining trend, pointing to persistent vulnerabilities.

  • A dashed reference line at 0% marks the divide between economic contraction and expansion, with most points staying above it, reflecting overall growth despite challenges.

The analysis underscores the pandemic’s significant impact and a slow recovery trajectory in economic activity.

Comparison with CFNAIDIFF

# Load CFNAIDIFF
getSymbols("CFNAIDIFF", src = "FRED", return.class = 'xts', from = "2010-01-01")
[1] "CFNAIDIFF"
cfnaidiff_ss <- CFNAIDIFF["2010-05-01/2024-09-01"] |> ts_ts()
min_length <- min(length(ma_index), length(cfnaidiff_ss))
ma_index <- ma_index[1:min_length]
cfnaidiff_ss <- cfnaidiff_ss[1:min_length]
Date <- Date[1:min_length]

# Prepare the comparison data frame
compare_df <- cbind.data.frame(Date, diffusion_index = ma_index, CFNAIDIFF = cfnaidiff_ss)

correlation <- cor(compare_df$diffusion_index, compare_df$CFNAIDIFF, use = "complete.obs")

# Enhanced comparison plot with interactivity
plotly::ggplotly(
  ggplot() +
    geom_line(data = compare_df, aes(x = Date, y = diffusion_index, color = "Diffusion Index"), size = 1.2) +
    geom_line(data = compare_df, aes(x = Date, y = CFNAIDIFF * 100, color = "CFNAIDIFF"), size = 1.2, linetype = "dashed") +
    scale_color_manual(
      values = c("Diffusion Index" = "blue", "CFNAIDIFF" = "orange")
    ) +
    labs(
      title = "Comparison of Diffusion Index and CFNAIDIFF",
      x = "Year",
      y = "Index Value",
      color = "Legend"
    ) +
    theme_minimal(base_size = 14) +
    theme(
      plot.title = element_text(size = 18, face = "bold", hjust = 0.5),
      legend.position = "bottom"
    )
)

Comparing the Diffusion Index and CFNAIDIFF (2010-2025)

This analysis highlights the differences between the Diffusion Index (blue solid line) and CFNAIDIFF (orange dashed line):

  • Volatility: The Diffusion Index shows sharp peaks and troughs, reflecting localized or sector-specific trends, while CFNAIDIFF remains steadier, indicating broader national trends.

  • Pre-2015: The Diffusion Index consistently outpaces CFNAIDIFF, signaling stronger localized economic growth.

  • 2015-2020: Both indices decline, with CFNAIDIFF dipping into negative territory, reflecting below-average national growth before COVID-19.

  • COVID-19 (2020): Both indices plummet, but the Diffusion Index recovers faster, suggesting localized resilience.

  • 2020-2025: The Diffusion Index trends downward, reflecting localized weaknesses, while CFNAIDIFF stabilizes, indicating national-level steadiness.

Insights:

The Diffusion Index captures localized nuances, while CFNAIDIFF provides a broader, smoother view of economic activity. Their divergence underscores the importance of using both measures for a comprehensive economic analysis.

Correlation Output

paste("Correlation between diffusion index and CFNAIDIFF:", round(correlation, 3))
[1] "Correlation between diffusion index and CFNAIDIFF: 0.157"

Conclusion

  • Diffusion Index:

    • Reflects significant economic fluctuations over time.

    • Indicates recent weakening, driven by declines in employment, industrial production, and consumer sentiment.

  • CFNAIDIFF:

    • Highlights steadier national activity.

    • Less volatile compared to the diffusion index.

  • Correlation:

    • Weak correlation (0.157) underscores differences in focus:

      • Diffusion Index is more sensitive to localized economic shifts.

      • CFNAIDIFF captures broader national trends.

  • Outlook:

    • The diffusion index signals regional or sectoral weaknesses.

    • CFNAIDIFF suggests a stable national economy, with no widespread contraction.