library(completejourney)
library(dplyr)
library(ggplot2)
# Load the sample datasets provided by completejourney
data("transactions_sample")
data("products")
data("demographics")
income_products <- transactions_sample %>%
left_join(products, by = "product_id") %>%
left_join(demographics, by = "household_id") %>%
group_by(income, product_category) %>%
summarise(total_sales_value = sum(sales_value, na.rm = TRUE)) %>%
arrange(desc(total_sales_value)) %>%
group_by(income) %>%
top_n(5, total_sales_value)
`summarise()` has grouped output by 'income'. You can override using the `.groups` argument.
ggplot(income_products, aes(x = reorder(product_category, total_sales_value), y = total_sales_value, fill = income)) +
geom_bar(stat = "identity", position = position_dodge(width = 0.8)) + # Dodge for side-by-side bars
labs(title = "Top 5 Products Purchased by Income Level",
subtitle = "Total sales value comparison across income groups",
x = "Product Category", y = "Total Sales Value") +
theme_minimal() +
theme(
plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
axis.text.x = element_text(angle = 45, hjust = 1, size = 10), # Adjust rotation for x-axis labels
axis.text.y = element_text(size = 10),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
legend.position = "right"
)

# Plot 2: Customer Loyalty vs. Purchase Frequency
ggplot(loyalty_data, aes(x = as.factor(loyalty), y = purchase_frequency, fill = as.factor(loyalty))) +
geom_boxplot() +
labs(title = "Customer Loyalty vs. Purchase Frequency",
subtitle = "Distribution of purchase frequency by household size",
x = "Household Size (Loyalty)", y = "Purchase Frequency") +
theme_minimal() +
theme(
plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
axis.text.x = element_text(size = 10),
axis.text.y = element_text(size = 10),
axis.title.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
legend.position = "none"
)

# Ensure that the transaction_timestamp is in POSIXct format
transactions_sample <- transactions_sample %>%
mutate(transaction_timestamp = as.POSIXct(transaction_timestamp, format = "%Y-%m-%d %H:%M:%S"))
# If the format only has the date part, use this:
# transactions_sample <- transactions_sample %>%
# mutate(transaction_timestamp = as.POSIXct(transaction_timestamp, format = "%Y-%m-%d"))
# Aggregate spending by month and region
monthly_spending <- transactions_sample %>%
left_join(demographics, by = "household_id") %>%
mutate(month = format(transaction_timestamp, "%Y-%m")) %>% # Extract month directly as a string
group_by(month, region = home_ownership) %>%
summarise(total_spending = sum(sales_value, na.rm = TRUE)) %>%
ungroup()
`summarise()` has grouped output by 'month'. You can override using the `.groups` argument.
# Convert month back to date format (if necessary) for plotting
monthly_spending$month <- as.Date(paste0(monthly_spending$month, "-01"), format = "%Y-%m-%d")
# Plot the monthly spending pattern
ggplot(monthly_spending, aes(x = month, y = total_spending, color = region)) +
geom_line(size = 1.2) +
labs(title = "Monthly Spending Patterns Across Regions",
subtitle = "Analysis of spending patterns by region over time",
x = "Month", y = "Total Spending") +
theme_light() +
theme(
plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
axis.text.x = element_text(angle = 45, hjust = 1),
panel.grid.major = element_line(color = "grey80")
)
Warning: Removed 12 rows containing missing values or values outside the scale range (`geom_line()`).

LS0tDQp0aXRsZTogIkNvbXBsZXRlSm91cm5leSBEYXRhIFZpc3VhbGl6YXRpb24iDQphdXRob3I6ICJSYXVzaGFuIFRld2FyeSINCmRhdGU6ICIyMDI0LTA5LTMwIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KYGBge3J9DQpsaWJyYXJ5KGNvbXBsZXRlam91cm5leSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiMgTG9hZCB0aGUgc2FtcGxlIGRhdGFzZXRzIHByb3ZpZGVkIGJ5IGNvbXBsZXRlam91cm5leQ0KZGF0YSgidHJhbnNhY3Rpb25zX3NhbXBsZSIpDQpkYXRhKCJwcm9kdWN0cyIpDQpkYXRhKCJkZW1vZ3JhcGhpY3MiKQ0KaW5jb21lX3Byb2R1Y3RzIDwtIHRyYW5zYWN0aW9uc19zYW1wbGUgJT4lDQogIGxlZnRfam9pbihwcm9kdWN0cywgYnkgPSAicHJvZHVjdF9pZCIpICU+JQ0KICBsZWZ0X2pvaW4oZGVtb2dyYXBoaWNzLCBieSA9ICJob3VzZWhvbGRfaWQiKSAlPiUNCiAgZ3JvdXBfYnkoaW5jb21lLCBwcm9kdWN0X2NhdGVnb3J5KSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsX3NhbGVzX3ZhbHVlID0gc3VtKHNhbGVzX3ZhbHVlLCBuYS5ybSA9IFRSVUUpKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsX3NhbGVzX3ZhbHVlKSkgJT4lDQogIGdyb3VwX2J5KGluY29tZSkgJT4lDQogIHRvcF9uKDUsIHRvdGFsX3NhbGVzX3ZhbHVlKQ0KZ2dwbG90KGluY29tZV9wcm9kdWN0cywgYWVzKHggPSByZW9yZGVyKHByb2R1Y3RfY2F0ZWdvcnksIHRvdGFsX3NhbGVzX3ZhbHVlKSwgeSA9IHRvdGFsX3NhbGVzX3ZhbHVlLCBmaWxsID0gaW5jb21lKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpICsgICMgRG9kZ2UgZm9yIHNpZGUtYnktc2lkZSBiYXJzDQogIGxhYnModGl0bGUgPSAiVG9wIDUgUHJvZHVjdHMgUHVyY2hhc2VkIGJ5IEluY29tZSBMZXZlbCIsDQogICAgICAgc3VidGl0bGUgPSAiVG90YWwgc2FsZXMgdmFsdWUgY29tcGFyaXNvbiBhY3Jvc3MgaW5jb21lIGdyb3VwcyIsDQogICAgICAgeCA9ICJQcm9kdWN0IENhdGVnb3J5IiwgeSA9ICJUb3RhbCBTYWxlcyBWYWx1ZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgaGp1c3QgPSAwLjUpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDEwKSwgICMgQWRqdXN0IHJvdGF0aW9uIGZvciB4LWF4aXMgbGFiZWxzDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwNCiAgICBsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiDQogICkNCg0KIyBQbG90IDI6IEN1c3RvbWVyIExveWFsdHkgdnMuIFB1cmNoYXNlIEZyZXF1ZW5jeQ0KbG95YWx0eV9kYXRhIDwtIHRyYW5zYWN0aW9uc19zYW1wbGUgJT4lDQogIGxlZnRfam9pbihkZW1vZ3JhcGhpY3MsIGJ5ID0gImhvdXNlaG9sZF9pZCIpICU+JQ0KICBncm91cF9ieShob3VzZWhvbGRfaWQsIGxveWFsdHkgPSBob3VzZWhvbGRfc2l6ZSkgJT4lDQogIHN1bW1hcmlzZShwdXJjaGFzZV9mcmVxdWVuY3kgPSBuKCkpICU+JQ0KICB1bmdyb3VwKCkNCmdncGxvdChsb3lhbHR5X2RhdGEsIGFlcyh4ID0gYXMuZmFjdG9yKGxveWFsdHkpLCB5ID0gcHVyY2hhc2VfZnJlcXVlbmN5LCBmaWxsID0gYXMuZmFjdG9yKGxveWFsdHkpKSkgKw0KICBnZW9tX2JveHBsb3QoKSArDQogIGxhYnModGl0bGUgPSAiQ3VzdG9tZXIgTG95YWx0eSB2cy4gUHVyY2hhc2UgRnJlcXVlbmN5IiwNCiAgICAgICBzdWJ0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgcHVyY2hhc2UgZnJlcXVlbmN5IGJ5IGhvdXNlaG9sZCBzaXplIiwNCiAgICAgICB4ID0gIkhvdXNlaG9sZCBTaXplIChMb3lhbHR5KSIsIHkgPSAiUHVyY2hhc2UgRnJlcXVlbmN5IikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZSgNCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUpLA0KICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEwKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTApLA0KICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpLA0KICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIg0KICApDQoNCiMgRW5zdXJlIHRoYXQgdGhlIHRyYW5zYWN0aW9uX3RpbWVzdGFtcCBpcyBpbiBQT1NJWGN0IGZvcm1hdA0KdHJhbnNhY3Rpb25zX3NhbXBsZSA8LSB0cmFuc2FjdGlvbnNfc2FtcGxlICU+JQ0KICBtdXRhdGUodHJhbnNhY3Rpb25fdGltZXN0YW1wID0gYXMuUE9TSVhjdCh0cmFuc2FjdGlvbl90aW1lc3RhbXAsIGZvcm1hdCA9ICIlWS0lbS0lZCAlSDolTTolUyIpKQ0KDQojIElmIHRoZSBmb3JtYXQgb25seSBoYXMgdGhlIGRhdGUgcGFydCwgdXNlIHRoaXM6DQojIHRyYW5zYWN0aW9uc19zYW1wbGUgPC0gdHJhbnNhY3Rpb25zX3NhbXBsZSAlPiUNCiMgICBtdXRhdGUodHJhbnNhY3Rpb25fdGltZXN0YW1wID0gYXMuUE9TSVhjdCh0cmFuc2FjdGlvbl90aW1lc3RhbXAsIGZvcm1hdCA9ICIlWS0lbS0lZCIpKQ0KIyBBZ2dyZWdhdGUgc3BlbmRpbmcgYnkgbW9udGggYW5kIHJlZ2lvbg0KbW9udGhseV9zcGVuZGluZyA8LSB0cmFuc2FjdGlvbnNfc2FtcGxlICU+JQ0KICBsZWZ0X2pvaW4oZGVtb2dyYXBoaWNzLCBieSA9ICJob3VzZWhvbGRfaWQiKSAlPiUNCiAgbXV0YXRlKG1vbnRoID0gZm9ybWF0KHRyYW5zYWN0aW9uX3RpbWVzdGFtcCwgIiVZLSVtIikpICU+JSAgIyBFeHRyYWN0IG1vbnRoIGRpcmVjdGx5IGFzIGEgc3RyaW5nDQogIGdyb3VwX2J5KG1vbnRoLCByZWdpb24gPSBob21lX293bmVyc2hpcCkgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9zcGVuZGluZyA9IHN1bShzYWxlc192YWx1ZSwgbmEucm0gPSBUUlVFKSkgJT4lDQogIHVuZ3JvdXAoKQ0KDQojIENvbnZlcnQgbW9udGggYmFjayB0byBkYXRlIGZvcm1hdCAoaWYgbmVjZXNzYXJ5KSBmb3IgcGxvdHRpbmcNCm1vbnRobHlfc3BlbmRpbmckbW9udGggPC0gYXMuRGF0ZShwYXN0ZTAobW9udGhseV9zcGVuZGluZyRtb250aCwgIi0wMSIpLCBmb3JtYXQgPSAiJVktJW0tJWQiKQ0KIyBQbG90IHRoZSBtb250aGx5IHNwZW5kaW5nIHBhdHRlcm4NCmdncGxvdChtb250aGx5X3NwZW5kaW5nLCBhZXMoeCA9IG1vbnRoLCB5ID0gdG90YWxfc3BlbmRpbmcsIGNvbG9yID0gcmVnaW9uKSkgKw0KICBnZW9tX2xpbmUoc2l6ZSA9IDEuMikgKw0KICBsYWJzKHRpdGxlID0gIk1vbnRobHkgU3BlbmRpbmcgUGF0dGVybnMgQWNyb3NzIFJlZ2lvbnMiLA0KICAgICAgIHN1YnRpdGxlID0gIkFuYWx5c2lzIG9mIHNwZW5kaW5nIHBhdHRlcm5zIGJ5IHJlZ2lvbiBvdmVyIHRpbWUiLA0KICAgICAgIHggPSAiTW9udGgiLCB5ID0gIlRvdGFsIFNwZW5kaW5nIikgKw0KICB0aGVtZV9saWdodCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIsIGhqdXN0ID0gMC41KSwNCiAgICBwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiwgaGp1c3QgPSAwLjUpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmV5ODAiKQ0KICApDQpgYGA=