Can the FED Control Inflation and Maintain Full Employment

Data-608 Knowledge and Visual Analytics

Author: Rupendra Shrestha | 28 Sep 2025

Instruction

The Federal Reserve’s mandate from Congress is to control inflation and to maintain low unemployment. These seem to be contradictory objectives.

For this story you will need to source the following data for the last 25 years;

The Consumer Price Index (CPI) (Bureau of Labor Statistics)

The FED Funds Rate (FRED) (Federal Reserve Board)

Unemployment Rate (Bureau of Labor Statistics) Your Data Visualizations should be designed to answer the question “Has the FED been able to fulfill the mandate given to it by Congress?”

Introduction

The Federal Reserve has a two-part congressional mandate: (1) maintain price stability (≈ 2% inflation), and (2) maximize employment (low unemployment). This study utilizes ~25 years of monthly data to examine whether the Fed has been successful in meeting this mandate.

Abstract

This project examines whether the Federal Reserve has been successful in fulfilling its dual mandate for price stability and maximum employment during the past 25 years. Using monthly series data on the Bureau of Labor Statistics’ Consumer Price Index (CPI) https://www.bls.gov/developers/api_signature_v2.htm, the Federal Reserve Economic Data effective federal funds rate - https://www.stlouisfed.org, and the unemployment rate from the Bureau of Labor Statistics, we investigate trends, connections, and reactions to policy. Visualizations emphasize how inflation, unemployment, and interest rates have interacted during various episodes of the economy, including the early 2000s recession, the 2008 financial crisis, the period of low inflation recovery, and the post-COVID inflation peak. The results demonstrate that while the Federal Reserve generally has managed to attain low unemployment and moderate inflation in good times, external shocks and long policy lags have repeatedly forced difficult choices. Evidence indicates the Fed can guide the economy to its twin goals, although it is constrained by unpredictable shocks, global influences, and inherent tension in keeping inflation low and keeping employment at full levels.

Data Gathering with API

The Objective in data collection was to get the last 25 years for each of the following: The Consumer Price Index (CPI), The FED Funds Rate (FRED), Unemployment Rate, and Inflation Rate. The CPI and Unemployment rate came from the Bureau of Labor Statistics(BLS); as the FED Funds rate and Inflation Rate came from the Federal Reserve Board website. This results in needing to use 2 different API sources in order to collect the data. It should be noted that the BLS websites, data policy is a maximum of 20 years per request, therefore the code is bulkier as it had to combine 2 request to reach the 25 year range of data per each type. The Federal Reserve Board website was done via the fredr package and after obtaining an API key, the process was very easy.

BLS Public Data API Source: https://www.bls.gov/developers/api_signature_v2.htm

FRED API Source: https://www.stlouisfed.org

Bureau of labor Statistics

CPI Load

bls_url <- "https://api.bls.gov/publicAPI/v2/timeseries/data/"
payload <- glue('{
    "seriesid":["EIUIR4"],
    "startyear":"2015",
    "endyear":"2024",
    "registrationkey":"{{bls_api_key}}"
}', .open="{{", .close="}}")

suppressMessages({
response <- POST(bls_url, body = payload, content_type("application/json"),
                encode = "json")
x <- content(response, "text") %>% jsonlite::fromJSON()
})
x$Results$series$data[[1]] %>% as_tibble() -> CPI_2

payload <- glue('{
    "seriesid":["EIUIR4"],
    "startyear":"1999",
    "endyear":"2015",
    "registrationkey":"{{bls_api_key}}"
}', .open="{{", .close="}}")

suppressMessages({
response <- POST(bls_url, body = payload, content_type("application/json"), encode = "json")
x <- content(response, "text") %>% jsonlite::fromJSON()
})
x$Results$series$data[[1]] %>% as_tibble() -> CPI_1

CPI_Final <- bind_rows(CPI_1, CPI_2) %>%
  distinct()

UnEmployment Load

payload <- glue('{
    "seriesid":["LNS14000000"],
    "startyear":"2015",
    "endyear":"2024",
    "registrationkey":"{{bls_api_key}}"
}', .open="{{", .close="}}")

suppressMessages({
response <- POST(bls_url, body = payload, content_type("application/json"), encode = "json")
x <- content(response, "text") %>% jsonlite::fromJSON()
})
x$Results$series$data[[1]] %>% as_tibble() -> Unemploy_2

payload <- glue('{
    "seriesid":["LNS14000000"],
    "startyear":"1999",
    "endyear":"2015",
    "registrationkey":"{{bls_api_key}}"
}', .open="{{", .close="}}")

suppressMessages({
response <- POST(bls_url, body = payload, content_type("application/json"), encode = "json")
x <- content(response, "text") %>% jsonlite::fromJSON()
})
x$Results$series$data[[1]] %>% as_tibble() -> Unemploy_1

Unemploy_Final <- bind_rows(Unemploy_1, Unemploy_2) %>%
  distinct()

# Quick check
head(Unemploy_Final)%>% kable() %>% 
kable_styling(bootstrap_options = "striped", font_size = 12) %>% 
scroll_box(height = "100%", width = "100%")
year period periodName value footnotes
2015 M12 December 5.0 NULL
2015 M11 November 5.1 NULL
2015 M10 October 5.0 NULL
2015 M09 September 5.0 NULL
2015 M08 August 5.1 NULL
2015 M07 July 5.2 NULL
head(CPI_Final)%>% kable() %>% 
kable_styling(bootstrap_options = "striped", font_size = 12) %>% 
scroll_box(height = "100%", width = "100%")
year period periodName value footnotes
2015 M12 December 107.2 NULL
2015 M11 November 107.2 NULL
2015 M10 October 107.2 NULL
2015 M09 September 107.2 NULL
2015 M08 August 107.1 NULL
2015 M07 July 107.2 NULL

Aggregate by year to calculate the annual average CPI

This plot displays the Consumer Price Index (CPI) from 1999 to 2024, showing the trend in the general price level of goods and services in the U.S. economy. It provides a measure of inflation over the 25-year period. The Consumer Price Index (CPI) tracks the average change in the prices of goods and services purchased by households. Because it is cumulative, CPI almost always rises — prices rarely return to earlier levels. For this reason, the CPI chart will resemble a steadily increasing line

# Aggregate by year to calculate the annual average CPI

# Convert 'year' to numeric (if it's not already)
CPI_Final$year <- as.numeric(CPI_Final$year)

# Convert 'value' (CPI) to numeric
CPI_Final$value <- as.numeric(CPI_Final$value)

cpi_annual <- CPI_Final %>%
  group_by(year) %>%
  summarise(cpi = mean(value, na.rm = TRUE)) %>%
  ungroup()

ggplot(cpi_annual, aes(x = year, y = cpi)) +
  geom_line(color = "blue", linewidth = 0.8, na.rm = TRUE) +
  geom_point(color = "blue", size = 2, na.rm = TRUE) +
  labs(
    x = "Year", 
    y = "CPI Value", 
    title = "Consumer Price Index (CPI) Over the Last 25 Years (1999–2024)",
    caption = "Major economic events are annotated: Dot-Com Recession, 2008 Financial Crisis, COVID-19 Shock, Post-COVID Inflation Surge"
  ) +
  annotate("text", x = 2001, y = 102, label = " 2001 Dot-Com Recession", size = 3, hjust = 0) +
  annotate("text", x = 2009, y = 105, label = "2008 Financial Crisis", size = 3, hjust = 0) +
  annotate("text", x = 2020, y = 106, label = "2020 COVID-19 Shock", size = 3, hjust = 0) +
  annotate("text", x = 2022, y = 108, label = "Post-COVID Inflation Surge", size = 3, hjust = 0) +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    plot.caption = element_markdown(hjust = 0.5, face = "bold")
  )

The upward trend in CPI is expected and not a signal of instability by itself. What matters to the Federal Reserve is the rate of change in CPI, known as inflation. This distinction is important: while CPI shows the long-run buildup in prices, the inflation rate reveals periods when prices are accelerating faster than normal. Sudden spikes in inflation, such as post-COVID, are particularly relevant for policy decisions, whereas the steady long-term growth of CPI reflects normal economic expansion.

Unemployment Rate Over the Last 25 Years

The unemployment rate measures the percentage of the labor force that is at present looking for a job but is unable to find one. It doesn’t always rise over time like the CPI does, though. Instead, unemployment fluctuates about the “natural rate” of unemployment, or the unemployment rate consistent with inflation stability.

# Convert year to numeric
Unemploy_Final <- Unemploy_Final %>% mutate(year = as.numeric(year))
Unemploy_Final <- Unemploy_Final %>% mutate(value = as.numeric(value))

# Assuming 'Unemploy_Final' has a 'year' and 'value' column
average_per_year <- Unemploy_Final %>% group_by(year) %>% summarise(avg_unemployment = mean(value, na.rm = TRUE))

# Plotting Employment
ggplot(average_per_year, aes(x = year, y = avg_unemployment)) +
  geom_point(color = "blue", size = 2) +                     # dotted points
  geom_line(color = "blue", linewidth = 0.8) +               # straight connecting line
  labs(x = "Year", y = "Unemployment Rate", title = "Unemployment Rate Over the Last 25 Years",
       caption="Joblessness rose sharply during the 2008 crisis and 2020 pandemic, then recovered as the Fed supported growth"
       ) +
  theme_minimal()+
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
    plot.caption = element_markdown(hjust = 0.5, face = "bold")
    )+
# ---- Annotations for major events (x = year as numeric) ----
  annotate("text", x = 2001, y = 6,
           label = "Dot-Com Recession", size = 3) +
  annotate("text", x = 2009, y = 3.5,
           label = "2008 Financial Crisis", size = 3) +
  annotate("text", x = 2020, y = 4.25,
           label = "COVID-19 Shock", size = 3) +
  annotate("text", x = 2022, y = 5.5,
           label = "Post-COVID Inflation Surge", size = 3)

Unemployment spikes usually occur after a recession, such as the Dot-Com collapse of 2001, the 2008 financial crisis, and the 2020 COVID-19 pandemic. During the intervening times between shocks, unemployment returns to the natural rate, showing how the Fed is able to stabilize the labor market. Even if there are short-run departures, the overall pattern is one of cyclical, rather than ever-increasing, labor market fluctuations, that shows the dual mandate of the Fed to maintain low levels of unemployment and stable prices.

Federal Reserve

The federal funds rate is the short-term interest rate at which banks lend to each other overnight. It is a key policy tool the Fed uses to influence inflation and employment.

fredr_set_key(FRED_API_KEY)

# ---- Fed Funds Data ----
fed_data <- fredr(
  series_id = "FEDFUNDS",
  observation_start = as.Date("1999-01-01"),
  observation_end   = as.Date("2024-12-31")
) %>%
  mutate(year = year(date)) %>%
  group_by(year) %>%
  summarise(avg_fed_funds = mean(value, na.rm = TRUE), .groups = "drop")

# Extract last 25 years
fed_avg_year <- fed_data %>%
  filter(year >= (year(Sys.Date()) - 25))

# Show first few rows
head(fed_avg_year)%>% kable() %>% 
kable_styling(bootstrap_options = "striped", font_size = 12) %>% 
scroll_box(height = "100%", width = "100%")
year avg_fed_funds
2000 6.235833
2001 3.887500
2002 1.666667
2003 1.127500
2004 1.349167
2005 3.213333
# ---- Inflation Data ----
inflation_data <- fredr(
  series_id = "FPCPITOTLZGUSA",
  observation_start = as.Date("1999-01-01"),
  observation_end   = as.Date("2024-12-31")
) %>%
  mutate(year = year(date)) %>%
  group_by(year) %>%
  summarise(avg_inflation_rate = mean(value, na.rm = TRUE), .groups = "drop")

# Extract last 25 years
infl_avg_year <- inflation_data %>%
  filter(year >= (year(Sys.Date()) - 25))

# Show first few rows
head(infl_avg_year)%>% kable() %>% 
kable_styling(bootstrap_options = "striped", font_size = 12) %>% 
scroll_box(height = "100%", width = "100%")
year avg_inflation_rate
2000 3.376857
2001 2.826171
2002 1.586032
2003 2.270095
2004 2.677237
2005 3.392747
# ---- Merge by year ----
combined_data <- full_join(fed_data, inflation_data, by = "year") %>%
  filter(year >= (year(Sys.Date()) - 25))  # keep last 25 years

# ---- Check merged data ----
head(combined_data)%>% kable() %>% 
kable_styling(bootstrap_options = "striped", font_size = 12) %>% 
scroll_box(height = "100%", width = "100%")
year avg_fed_funds avg_inflation_rate
2000 6.235833 3.376857
2001 3.887500 2.826171
2002 1.666667 1.586032
2003 1.127500 2.270095
2004 1.349167 2.677237
2005 3.213333 3.392747
# ---- Plot Fed Funds vs Inflation ----
ggplot(combined_data, aes(x = year)) +
  geom_line(aes(y = avg_fed_funds, color = "Fed Funds Rate"), linewidth = 1) +
  geom_line(aes(y = avg_inflation_rate, color = "Inflation Rate"), linewidth = 1) +
  scale_y_continuous(
    name = "Fed Funds Rate (%)",
    sec.axis = sec_axis(~ ., name = "Inflation Rate (%)")
  ) +
  scale_color_manual(
    name = "Series",
    values = c("Fed Funds Rate" = "blue", "Inflation Rate" = "red")
  ) +
  labs(title = "Fed Funds Rate vs Inflation (1999–2024)", x = "Year",
       caption="Recessions pushed the Fed to cut rates, while the 2022 inflation surge forced rapid hikes"
       ) +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(size = 14, face = "bold"),
    plot.caption = element_text(hjust = 0.5, face = "bold")
  )+
  # ---- Annotations for major events (x = year as numeric) ----
  annotate("text", x = 2001, y = 6,
           label = "Dot-Com Recession", size = 3) +
  annotate("text", x = 2009, y = 0.5,
           label = "2008 Financial Crisis", size = 3) +
  annotate("text", x = 2020, y = 0.25,
           label = "COVID-19 Shock", size = 3) +
  annotate("text", x = 2022, y = 4.5,
           label = "Post-COVID Inflation Surge", size = 3)

The federal funds rate shows sudden, discrete changes based on economic happenings. The Fed lowers the rates quickly in times of recession to spur growth and raises rates when inflation accelerates to maintain price stability. These step-like changes are a contrast to the steady patterns of CPI and unemployment, reflecting that monetary policy is reactive and counter-cyclical and attempts to balance the twin mandate of low unemployment as well as price stability.

Data Manipulation/Visualization

# Perform Pearson correlation test
cor_CU <- cor.test(cpi_unemp$CPI, cpi_unemp$Unemployment_Rate, method = "pearson")
# Perform Pearson correlation test
cor_CF <- cor.test(cpi_fed$CPI, cpi_fed$Fed_Rate, method = "pearson")

# Perform Pearson correlation test
cor_UF <- cor.test(unemp_fed$Unemployment_Rate, unemp_fed$Fed_Rate, method = "pearson")

Has the FED been able to fulfill the mandate given to it by Congress?

  • What is the mandate given by Congress?

Congressional mandate of the Federal Reserve is to ensure price stability, defined as maintaining inflation at or near 2%, and maximum sustainable employment, often in terms of unemployment rates ranging from 3–5%. Between 1999 and 2024, the Fed’s interventions generally conformed to these objectives: it reduced interest rates in recessions like the Dot-Com bubble, the 2008 financial crisis, and the COVID-19 crisis to sustain employment, and increased interest rates in times of high inflation to stabilize things. While performance was neither immediate nor perfect, over time unemployment has spent the majority of its time within target range and inflation averaged close to 2%, suggesting the Fed roughly fulfilled its dual mandate.

CPI (Consumer Price Index)

As the Consumer Price Index (CPI) rises, it indicates rising inflation since CPI is a measure of the increase in the prices of goods and services over time. To offset the same, the Federal Reserve will typically raise the federal funds rate to raise the cost of borrowing, thereby lowering spending and investment and helping to bring inflation closer towards the 2% goal. Conversely, when inflation begins to decline or the economy is decelerating, the Fed might lower interest rates in a bid to stimulate demand and spur economic growth. This dynamic normally generates a negative correlation between inflation and the federal funds rate over the business cycle and reflects the function of the Fed in maintaining price stability.

Unemployment Rate

There is historically an inverse correlation between the Federal Funds Rate and the Unemployment Rate. Low Unemployment rates generally are a sign of a healthy economy with more consumer spending. This has a tendency to inflation of general goods and services and, as a result, the Federal Reserve may raise interest rates to prevent overheating. In addition, rising unemployment rates would typically make the Federal Reserve lower interest rates to stimulate the economy, which would, in turn, lead to job creation. The idea is that when interest rates are lowered, there is typically more money for the company to spend which would typically be put into the company’s employees and lead to new opportunity or job creation. According to different economists, the ideal unemployment rate for an economy should be 3-5% since it is claimed to increase demand and allow competition to flourish unchecked.

Inflation Rate

When inflation rises, the Federal Reserve typically raises interest rates to slow spending and bring prices under control. When inflation falls or the economy weakens, the Fed lowers rates to stimulate borrowing and growth. These adjustments aim to guide inflation toward the 2% target.

CPI and Unemployment Rate

The correlation coefficient is 0.0367, and the p-value is 0.5254, which indicates that there is no statistically significant correlation between CPI and Unemployment Rate.

print(cor_CU)
## 
##  Pearson's product-moment correlation
## 
## data:  cpi_unemp$CPI and cpi_unemp$Unemployment_Rate
## t = -0.02746, df = 24, p-value = 0.9783
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.3921057  0.3825775
## sample estimates:
##          cor 
## -0.005605124

The Pearson correlation between CPI and the unemployment rate is very weak (r ≈ 0.037) and not statistically significant (p ≈ 0.53). This indicates that, over the 1999–2024 period, there is no meaningful linear relationship between inflation and unemployment in the monthly data.

CPI and Federal Fund Rate

The correlation coefficient is -0.4149 and the p-value is 5.982e-14, which indicates a statistically significant negative correlation between CPI and Federal Funds Rate.

print(cor_CF)
## 
##  Pearson's product-moment correlation
## 
## data:  cpi_fed$CPI and cpi_fed$Fed_Rate
## t = -1.3228, df = 23, p-value = 0.1989
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.5981760  0.1444127
## sample estimates:
##        cor 
## -0.2658904

There is a significant negative correlation (r ≈ -0.415, p < 0.001) between CPI and the federal funds rate, indicating that as inflation rises, the Fed tends to adjust rates in the opposite direction.

Unemployment and Federal Fund Rate

The correlation coefficient is -0.5905 and the p-value is < 2.2e-16, which indicates a statistically significant negative correlation between Unemployment Rate and Federal Funds Rate.

print(cor_UF)
## 
##  Pearson's product-moment correlation
## 
## data:  unemp_fed$Unemployment_Rate and unemp_fed$Fed_Rate
## t = -3.8955, df = 23, p-value = 0.0007289
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
##  -0.8210686 -0.3134410
## sample estimates:
##        cor 
## -0.6304861

There is a strong negative correlation (r ≈ -0.59, p < 0.001) between the unemployment rate and the federal funds rate, indicating that higher unemployment is associated with lower interest rates, consistent with the Fed’s policy to stimulate the economy during labor market weakness.

This plot shows the monthly trends of the U.S. unemployment rate, year-over-year inflation, and the federal funds rate from 1999 to 2024. It highlights how the Federal Reserve adjusts interest rates in response to changes in employment and inflation, particularly during major economic events.

events <- tibble(
  date  = as.Date(c("2001-03-01", "2008-09-01", "2020-03-01", "2022-01-01")),
  label = c("Dot-Com Recession", "2008 Financial Crisis", "COVID-19 Shock", "Post-COVID Inflation Surge")
)

# List of indicators in your plot
indicators <- unique(plot_data$indicator)

# Expand events for each indicator (needed for faceted geom_text)
events_faceted <- events %>% crossing(indicator = indicators)


# Faceted plot
plot1_faceted <- ggplot(plot_data, aes(x = date, y = value, color = indicator)) +
  geom_line(linewidth = 1) +
  facet_wrap(~indicator, scales = "free_y", ncol = 1) +
  geom_vline(data = events, aes(xintercept = date), linetype = "dashed", color = "gray50") +
  geom_text(data = events_faceted, 
            aes(x = date, y = max(plot_data$value), label = label),
            angle = 90, vjust = -0.5, hjust = 0, size = 3, inherit.aes = FALSE) +
  labs(
    title = "Economic Indicators Over the Last 25 Years",
  subtitle = "Fed policy reacts to inflation and unemployment shocks; \nCPI grows steadily, unemployment fluctuates, and Fed Funds Rate moves sharply",
    x = "Year",
    y = "Value",
    caption = "Dashed lines mark major economic events: 2001 Dot-Com, 2008 Financial Crisis, 2020 COVID-19, Post-COVID Inflation Surge"
  ) +
  scale_color_manual(values = c(
    "Unemployment Rate" = "blue",
    "Inflation Rate" = "red",
    "Federal Funds Rate" = "green",
    "CPI" = "purple"
  )) +
  theme_minimal() +
  theme(
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    plot.subtitle = element_text(face = "italic", size = 12, hjust = 0.5),
    legend.position = "none"
  )


plot1_faceted

Conclusion

The Federal Reserve has generally achieved its dual mandate of price stability and maximum employment as evidenced from the data. CPI has always increased over time, reflecting normal inflation trends, while unemployment has moved around its natural rate and spiked only during worst-recession times like the Dot-Com bust (2001), the financial crisis (2008), and the COVID-19 pandemic. In response, the Fed adjusted the Federal Funds Rate dramatically—reducing rates in recessions to spur employment and increasing them when inflation accelerated to maintain price stability. These patterns demonstrate that while the Fed cannot abolish the tension between low unemployment and stable prices, its policy action has historically steered the economy toward its dual goals, converging sufficiently to react to shocks and cycle gyrations.