Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
< ! coffee girl>
For 2025 the overall CPI increased by a pretty moderate 2.7% (CPI-U for all urban consumers, December to December). The CPI measures the price change of a basket of goods over eight major categories: food & beverages, housing, apparel, transportation, medical care, recreation, education & communication, and other, over a large number of metropolitan statitical areas (MSA). Each month Bureau of Labor Statistics data collectors collect about 94,000 prices. For some items, prices are adjusted to remove the effect of a change of quality (for example today’s Toyota Corolla is a much different car than ten years ago). There are separate indices for over 200 items countrywide, and separate indices for the eight major categories by MSA.Of course what matters is price changes on the items YOU buy, and especially the items you buy frequently like food. Each individual item has its own reasons for its price changes – egg prices are affected by bird flu, coffee prices are affected by weather and geopolitical conditions in other countries, etc. These factors are beyond our control.
I was interested in comparing food price changes for common frequently purchased items. This is based on CPIs for countrywide data in categories like eggs. Of course I am not measuring YOUR specific egg purchase (such as store brand, organic, medium size, white, 12 count, at CTown in Intercourse, Pennsylvania).
I began with 11 years of December values of ten separate food categories and also the overall CPI-U, seasonally adjusted. The values I used are as follows (although I understand values change as there are changes to seasonal adjustment factors, weightings, etc.)
< ! cpi values>
For comparison purposes I set all eleven indices to a 100 index value at 2015, and I plotted them on a line graph. Each year’s value is now relative to 2015.< ! cpi 10 year graph>
On a ten-year basis, ground beef, eggs, and lettuce are running higher than the overall CPI. Those three food indices have experienced a lot of volatility. The pandemic year 2022 was the year of the largest increase for many foods. Interestingly, apple prices have gone down!Another way to look at this is to look at bar graphs with percentage changes. Here are graphs with percentage changes 2015 to 2025, 2024 to 2025, and 2021 to 2022:
< ! 10 year bar graph>
For 2025 compared with 2015, I was not aware how much the prices had risen for ground beef, lettuce, and eggs.For 2025 compared to 2024, the increase in prices for ground beef, eggs, and coffee have been much larger than the 2.7% overall increase in the CPI. This is probably no surprise if you are the household member doing the grocery shopping.
For 2022 versus 2021, the increase in all foods except ground beef exceeded the overall CPI. We probably remember this during the Covid pandemic years.
In the insurance world, the goods and services that insurance pays for have also increased by more than the overall CPI. For example, medical care costs, auto maintenance & repair costs, and building construction & repair costs have consistently outpaced the overall CPI. So don’t be surprised to see health insurance, auto insurance, and home insurance prices to continue to increase.
Here is the R code:
library(readxl)
library(dplyr)
library(tidyr)
library(ggplot2)
df <- read_excel("C:/Users/Jerry/Desktop/R_files/CPI_10_years.xlsx")
print(df, n = Inf, width = Inf)
# 1. Convert data to 'long' format for easier plotting
df_long < - df %>%
pivot_longer(cols = -Year, names_to = "Category", values_to = "Index")
# 2. Re-base every category so 2015 = 100
df_normalized < - df_long %>%
group_by(Category) %>%
mutate(Index_100 = (Index / Index[Year == 2015]) * 100) %>%
ungroup()
# 3. Plot line graph "Race to the Top"
ggplot(df_normalized, aes(x = Year, y = Index_100, color = Category)) +
geom_line(aes(size = Category == "Overall CPI"), show.legend = FALSE) +
# Use subset to only label the last point (2025)
geom_text(data = subset(df_normalized, Year == 2025),
aes(label = Category),
hjust = -0.1, # Push text to the right of the point
size = 4, face="bold",
show.legend = FALSE) +
# Fix X-Axis: No decimals, every year labeled
scale_x_continuous(breaks = seq(2015, 2025, 1), limits = c(2015, 2027)) +
# Highlight the Overall CPI in black/thicker line
scale_size_manual(values = c("TRUE" = 2.0, "FALSE" = 0.8)) +
scale_color_manual(values = c("Overall CPI" = "black",
"Eggs" = "red",
"Ground Beef" = "darkred",
"Apples" = "forestgreen",
"Milk" = "blue",
"Bread" = "orange",
"Coffee" = "brown",
"Lettuce" = "lightgreen",
"Soup" = "#008080",
"Breakfast Cereal" = "purple",
"Other Fresh Veg" = "gray")) +
theme_minimal() +
theme(
legend.position = "none", # Remove legend
plot.title = element_text(face = "bold", size = 16),
axis.title = element_text(face = "bold"),
axis.text = element_text(face = "bold"),
plot.margin = margin(r = 100), # Add space on the right for labels
panel.grid.minor = element_blank()
) +
coord_cartesian(clip = 'off') + # Prevent labels from being cut off
labs(title = "Cumulative Food Price Changes (2015 = 100)",
subtitle = "Food categories vs. Overall CPI Baseline",
y = "Index (2015 = 100)",
x = "Year")
#4 Plot bar graph with % changes
# filter data for start and end years
plot_cpi_change <- function(data, start_yr, end_yr) {
# 1. Prepare dynamic column names for the mutation step
start_col <- paste0("Yr", start_yr)
end_col <- paste0("Yr", end_yr)
# 2. Data Processing
df_bar < - data %>%
filter(Year %in% c(start_yr, end_yr)) %>%
pivot_longer(cols = -Year, names_to = "Category", values_to = "Index") %>%
pivot_wider(names_from = Year, names_prefix = "Yr", values_from = Index) %>%
# Use .data[[]] to dynamically reference the columns created by pivot_wider
mutate(Pct_Change = ((.data[[end_col]] - .data[[start_col]]) / .data[[start_col]]) * 100) %>%
mutate(Category = reorder(Category, -Pct_Change))
# 3. Visualization
ggplot(df_bar, aes(x = Category, y = Pct_Change, fill = Category)) +
geom_bar(stat = "identity", color = "black", size = 0.5) +
# Logic for text placement based on positive/negative change
geom_text(aes(label = paste0(round(Pct_Change, 1), "%"),
vjust = ifelse(Pct_Change >= 0, -0.5, 1.5)),
face = "bold", size = 4.5) +
scale_fill_manual(values = c("Overall CPI" = "black", "Soup" = "#008080", "Eggs" = "red",
"Ground Beef" = "darkred", "Apples" = "forestgreen", "Milk" = "blue",
"Bread" = "orange", "Coffee" = "brown", "Lettuce" = "lightgreen",
"Breakfast Cereal" = "purple", "Other Fresh Veg" = "gray")) +
theme_minimal() +
theme(legend.position = "none",
plot.title = element_text(face = "bold", size = 18, hjust = 0.5),
axis.title = element_text(face = "bold", size = 14),
axis.text.x = element_text(face = "bold", size = 11, angle = 45, hjust = 1),
axis.text.y = element_text(face = "bold", size = 11),
panel.grid.major.x = element_blank()) +
coord_cartesian(clip = 'off') +
labs(title = paste("CPI FOOD PRICE CHANGES (", start_yr, "TO", end_yr, ")"),
y = "PERCENT CHANGE (%)", x = "CATEGORY")
}
plot_cpi_change(df, 2015, 2025)
plot_cpi_change(df, 2024, 2025)
plot_cpi_change(df, 2021, 2022)
End
< >
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
