library(tidyverse)
library(dplyr)
library(lubridate)
library(ggplot2)
The business question I will be looking at is how transaction traffic differs from holidays vs non-holidays. I’m going to look at transaction numbers from several different holidays and see if there is a correlation between products bought and holidays they were around. I’m also going to see if there is any holiday that recieves more transactions than others. Overall I’m trying to find out if the amount of transactions on a holiday is different from a regular day, and how Regork could improve on this.
library(completejourney)
## Welcome to the completejourney package! Learn more about these data
## sets at http://bit.ly/completejourney.
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr 1.1.4 ✔ readr 2.1.5
## ✔ forcats 1.0.0 ✔ stringr 1.5.1
## ✔ ggplot2 3.5.1 ✔ tibble 3.2.1
## ✔ lubridate 1.9.3 ✔ tidyr 1.3.1
## ✔ purrr 1.0.2
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag() masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(dplyr)
library(lubridate)
library(ggplot2)
library(tab)
## Loading required package: knitr
transactions <- get_transactions()
products <- products
demographics <- demographics
transaction_data <- transactions %>%
left_join(products, by = "product_id")
transaction_data <- transaction_data %>%
mutate(transaction_date = ymd_hms(transaction_timestamp))
transaction_data <- transaction_data %>%
mutate(holiday_period = case_when(
transaction_date %within% interval(ymd("2017-11-23"), ymd("2017-11-24")) ~ "Thanksgiving",
transaction_date %within% interval(ymd("2017-12-24"), ymd("2017-12-26")) ~ "Christmas",
transaction_date %within% interval(ymd("2017-07-04"), ymd("2017-07-05")) ~ "Fourth of July",
transaction_date %within% interval(ymd("2017-02-14"), ymd("2017-02-15")) ~ "Valentine's Day",
transaction_date %within% interval(ymd("2017-10-31"), ymd("2017-11-01")) ~ "Halloween",
TRUE ~ "Non-Holiday"
))
holiday_sales <- transaction_data %>%
filter(holiday_period != "Non-Holiday")
holiday_summary <- holiday_sales %>%
group_by(product_type, holiday_period) %>%
summarize(total_transactions = n(), .groups = 'drop')
top_holiday_products <- holiday_summary %>%
group_by(product_type) %>%
summarize(total_transactions = sum(total_transactions), .groups = 'drop') %>%
top_n(10, total_transactions) %>%
pull(product_type)
filtered_holiday_summary <- holiday_summary %>%
filter(product_type %in% top_holiday_products)
holiday_data <- transaction_data %>%
filter(holiday_period != "Non-Holiday")
total_holiday_products <- holiday_data %>%
group_by(product_type) %>%
summarize(total_transactions = n(), .groups = 'drop')
bottom_10_products <- total_holiday_products %>%
arrange(total_transactions) %>%
distinct(product_type, .keep_all = TRUE) %>%
slice_head(n = 10)
# Bottom 10
filtered_bottom_holiday_summary <- holiday_data %>%
filter(product_type %in% bottom_10_products$product_type) %>%
group_by(product_type, holiday_period) %>%
summarize(total_transactions = n(), .groups = 'drop')
sales_trends <- transaction_data %>%
group_by(product_type, holiday_period) %>%
summarize(total_sales = sum(sales_value, na.rm = TRUE),
total_transactions = n()) %>%
arrange(desc(total_sales))
## `summarise()` has grouped output by 'product_type'. You can override using the
## `.groups` argument.
holiday_transaction_counts <- transaction_data %>%
group_by(holiday_period) %>%
summarize(total_transactions = n(), .groups = 'drop')
table(transaction_data$holiday_period)
##
## Christmas Fourth of July Halloween Non-Holiday Thanksgiving
## 4558 5578 3499 1450807 1994
## Valentine's Day
## 2871
ggplot(holiday_transaction_counts, aes(x = holiday_period, y = total_transactions, fill = holiday_period)) +
geom_bar(stat = "identity") +
theme_minimal() +
labs(title = "Number of Transactions by Holiday Period",
x = "Holiday Period",
y = "Total Transactions") +
scale_fill_brewer(palette = "Set2") +
theme(axis.text.x = element_text(angle = 45, hjust = 1))
This table shows the vast discrepency in purchases made on holidays vs non-holidays. Out of a total of 1,469,307 transactions, 98.7% of those came on a non-holiday. With Christmas, 4th of July, Halloween, Thanksgiving, and Valentines day coming in at .31%, .37%, .24%, .135%, and .195% respectively. The holiday ranges I have set up take up 11/365 days or 3% of the days in a year. However, Holiday purchases only make up 1.3% of the transaction which shows people are not buying as much on holidays. I’m going to figure out how Regork can imporve this by looking at the top 10 and bottom 10 purchased items to see if there is a pattern with what people are willing to buy around a holiday.
ggplot(filtered_holiday_summary, aes(x = product_type, y = total_transactions, fill = holiday_period)) +
geom_bar(stat = "identity", position = "dodge") +
theme_minimal() +
labs(title = "Top 10 Product Types Purchased During the Holidays",
x = "Product Type",
y = "Total Transactions") +
scale_fill_brewer(palette = "Set2") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 10))
This table shows the top 10 products bought around each holiday. What I notice right away is that the 4th of July is is first or second for every product. I believe this is because the 4th of July is a holiday around fun with friends rather than family. A lot of friends will get together, and each bring their own food or drinks. it’s also much more of a local holiday. So there is less plane rides or long drives needed to make and stop you from buying at your local Regork chain. Also for the fourth of July you buy things on the day much more than in advance like you would with Christmas or Halloween, where you buy presents and candy in advance. Christmas arguably being the most popular holiday and only leading in on product is concerning, and I think a way to address that would be to promote more snacks and soft drinks, as they were only leading in 2 liter soft drinks. Additionally they need to stay open on Christmas to ensure they can capitalize off of people and families that want to snack and hang around after presents and lunch or dinner.
ggplot(filtered_bottom_holiday_summary, aes(x = product_type, y = total_transactions, fill = holiday_period)) +
geom_bar(stat = "identity", position = "dodge") +
theme_minimal() +
labs(title = "Bottom 10 Product Types Purchased During Holidays",
x = "Product Type",
y = "Total Transactions") +
scale_fill_brewer(palette = "Set2") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 10),
legend.title = element_blank()) +
coord_cartesian(ylim = c(0, max(filtered_bottom_holiday_summary$total_transactions) * 1.1))
The bottom 10 product types were very difficult. With the already limited amount of transactions around the holidays, combined with multiple products only being bought once, leading me to have to leave it to 10 unique products instead of all products with one we can deduct a couple of things from this data. The 4th of July being on here 3 times is very surprising to me. Especially wehn you take into account what the products are; rug care, Liquid bleach, and ant and roach repellent. This seems like people who didn’t go out to celebrate the 4th and had people over and needed to clean up the house for the guests. I think that is a big opportunity for marketing to capitalize on. The next thing I notice is Valentine’s Day only has 1 product on here. It makes complete sense to me, because it’s most likely guys who needed their place to smell better for Valentine’s Day. That is again another huge marketing opportunity for Regork because some guys don’t have the nicest smelling place and need it to be better, even when it’s not around Valentine’s Day.