Coupons Used per Income Bracket
#Libraries
library(completejourney)
library(dplyr)
library(ggplot2)
#Data
transactions <- get_transactions()
promotions <- get_promotions()
demographics <- demographics
coupon_redemptions <-coupon_redemptions
campaigns <- campaigns
# Data Cleaning
demographics$income <- gsub("[^0-9.]", "", demographics$income)
demographics$income <- as.numeric(demographics$income)
#Remove NA
demographics <- demographics[!is.na(demographics$income), ]
# Income Brackets
demographics$income_bracket <- cut(demographics$income,
breaks = c(0, 50000, 100000, 150000, 200000, 250000, Inf),
labels = c("> $50K", "$50K-$100K", "$100K-$150K", "$150K-$200K", "$200K-$250K", ">$250K"),
right = FALSE)
# Merge
household_coupons <- coupon_redemptions %>%
inner_join(demographics, by = "household_id") %>%
group_by(income_bracket) %>%
summarize(total_coupons_used = n())
# Visualization
p <- ggplot(household_coupons, aes(x = income_bracket, y = total_coupons_used, fill = income_bracket)) +
geom_bar(stat = "identity", fill = "grey80") +
geom_point(aes(color = income_bracket), size = 3)
p + geom_text(aes(label = total_coupons_used), vjust = -0.5) +
annotate("text", x = 2, y = 1500, label = "Highest usage here", color = "black", size = 3, angle = 360, fontface = "italic")

Spending by Household Composition
household_spending <- transactions %>%
inner_join(demographics, by = "household_id") %>%
group_by(household_comp) %>%
summarize(average_spending = mean(sales_value, na.rm = TRUE))
#Order
household_spending$household_comp <- factor(household_spending$household_comp,
levels = unique(demographics$household_comp[order(demographics$household_size)]))
#Visualization
spending_plot <- ggplot(household_spending, aes(x = household_comp, y = average_spending)) +
geom_col(fill = "grey80", color = "black") +
geom_point(aes(y = average_spending), color = "red", size = 3, show.legend = FALSE) +
geom_text(aes(label = round(average_spending, 2)), vjust = -2, color = "black") +
labs(title = "Average Household Spending by Composition",
x = "Household Composition",
y = "Average Spending ($)") +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
axis.title = element_text(face = "bold", size = 12),
axis.text.x = element_text(angle = 45, hjust = 1, vjust = 1),
axis.text.y = element_text(color = "black"),
panel.background = element_rect(fill = "white", colour = "grey50"), #
panel.grid.major = element_line(color = "grey90"),
panel.grid.minor = element_blank()
)
print(spending_plot)

Coupon Usage Between Households With and Without Children
#Filter
demographics$has_children <- ifelse(demographics$kids_count > 0, "With Children", "No Children")
# Merge
household_coupons <- coupon_redemptions %>%
inner_join(demographics, by = "household_id") %>%
group_by(has_children) %>%
summarize(total_coupons_used = n(), num_households = n_distinct(household_id), .groups = 'drop') %>%
mutate(average_coupons_per_household = total_coupons_used / num_households)
#Visualization
colors_for_children_status <- c("With Children" = "#56B4E9", "No Children" = "#E69F00")
coupon_usage_plot <- ggplot(household_coupons, aes(x = has_children, y = average_coupons_per_household, fill = has_children)) +
geom_col(show.legend = FALSE) +
scale_fill_manual(values = colors_for_children_status) +
geom_text(aes(label = round(average_coupons_per_household, 2)), vjust = -0.5, color = "white") +
labs(title = "Average Coupon Usage per Household by Child Status",
x = "Household Child Status",
y = "Average Coupons Used per Household") +
theme_minimal() +
theme(
plot.title = element_text(face = "bold", hjust = 0.5, size = 16),
axis.title = element_text(face = "bold", size = 12),
axis.text.x = element_text(angle = 0, hjust = 0.5),
axis.text.y = element_text(color = "black"),
panel.background = element_rect(fill = "white", colour = "grey50"),
panel.grid.major = element_line(color = "grey90"),
panel.grid.minor = element_blank()
)
print(coupon_usage_plot)

LS0tDQp0aXRsZTogIk1vZHVsZSA1IExhYiINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCkNvdXBvbnMgVXNlZCBwZXIgSW5jb21lIEJyYWNrZXQNCg0KYGBge3J9DQojTGlicmFyaWVzDQpsaWJyYXJ5KGNvbXBsZXRlam91cm5leSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQoNCiNEYXRhDQp0cmFuc2FjdGlvbnMgPC0gZ2V0X3RyYW5zYWN0aW9ucygpDQpwcm9tb3Rpb25zIDwtIGdldF9wcm9tb3Rpb25zKCkNCmRlbW9ncmFwaGljcyA8LSBkZW1vZ3JhcGhpY3MNCmNvdXBvbl9yZWRlbXB0aW9ucyA8LWNvdXBvbl9yZWRlbXB0aW9ucw0KY2FtcGFpZ25zIDwtIGNhbXBhaWducw0KDQojIERhdGEgQ2xlYW5pbmcNCmRlbW9ncmFwaGljcyRpbmNvbWUgPC0gZ3N1YigiW14wLTkuXSIsICIiLCBkZW1vZ3JhcGhpY3MkaW5jb21lKQ0KZGVtb2dyYXBoaWNzJGluY29tZSA8LSBhcy5udW1lcmljKGRlbW9ncmFwaGljcyRpbmNvbWUpDQoNCiNSZW1vdmUgTkENCmRlbW9ncmFwaGljcyA8LSBkZW1vZ3JhcGhpY3NbIWlzLm5hKGRlbW9ncmFwaGljcyRpbmNvbWUpLCBdDQoNCiMgSW5jb21lIEJyYWNrZXRzDQpkZW1vZ3JhcGhpY3MkaW5jb21lX2JyYWNrZXQgPC0gY3V0KGRlbW9ncmFwaGljcyRpbmNvbWUsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMCwgNTAwMDAsIDEwMDAwMCwgMTUwMDAwLCAyMDAwMDAsIDI1MDAwMCwgSW5mKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiPiAkNTBLIiwgIiQ1MEstJDEwMEsiLCAiJDEwMEstJDE1MEsiLCAiJDE1MEstJDIwMEsiLCAiJDIwMEstJDI1MEsiLCAiPiQyNTBLIiksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2h0ID0gRkFMU0UpDQojIE1lcmdlDQpob3VzZWhvbGRfY291cG9ucyA8LSBjb3Vwb25fcmVkZW1wdGlvbnMgJT4lDQogIGlubmVyX2pvaW4oZGVtb2dyYXBoaWNzLCBieSA9ICJob3VzZWhvbGRfaWQiKSAlPiUNCiAgZ3JvdXBfYnkoaW5jb21lX2JyYWNrZXQpICU+JQ0KICBzdW1tYXJpemUodG90YWxfY291cG9uc191c2VkID0gbigpKQ0KDQojIFZpc3VhbGl6YXRpb24gDQpwIDwtIGdncGxvdChob3VzZWhvbGRfY291cG9ucywgYWVzKHggPSBpbmNvbWVfYnJhY2tldCwgeSA9IHRvdGFsX2NvdXBvbnNfdXNlZCwgZmlsbCA9IGluY29tZV9icmFja2V0KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJncmV5ODAiKSArDQogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gaW5jb21lX2JyYWNrZXQpLCBzaXplID0gMykgIA0KcCArIGdlb21fdGV4dChhZXMobGFiZWwgPSB0b3RhbF9jb3Vwb25zX3VzZWQpLCB2anVzdCA9IC0wLjUpICsNCiAgYW5ub3RhdGUoInRleHQiLCB4ID0gMiwgeSA9IDE1MDAsIGxhYmVsID0gIkhpZ2hlc3QgdXNhZ2UgaGVyZSIsIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDMsIGFuZ2xlID0gMzYwLCBmb250ZmFjZSA9ICJpdGFsaWMiKQ0KDQpgYGANCg0KU3BlbmRpbmcgYnkgSG91c2Vob2xkIENvbXBvc2l0aW9uDQpgYGB7cn0NCmhvdXNlaG9sZF9zcGVuZGluZyA8LSB0cmFuc2FjdGlvbnMgJT4lDQogIGlubmVyX2pvaW4oZGVtb2dyYXBoaWNzLCBieSA9ICJob3VzZWhvbGRfaWQiKSAlPiUNCiAgZ3JvdXBfYnkoaG91c2Vob2xkX2NvbXApICU+JQ0KICBzdW1tYXJpemUoYXZlcmFnZV9zcGVuZGluZyA9IG1lYW4oc2FsZXNfdmFsdWUsIG5hLnJtID0gVFJVRSkpDQoNCiNPcmRlcg0KaG91c2Vob2xkX3NwZW5kaW5nJGhvdXNlaG9sZF9jb21wIDwtIGZhY3Rvcihob3VzZWhvbGRfc3BlbmRpbmckaG91c2Vob2xkX2NvbXAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsZXZlbHMgPSB1bmlxdWUoZGVtb2dyYXBoaWNzJGhvdXNlaG9sZF9jb21wW29yZGVyKGRlbW9ncmFwaGljcyRob3VzZWhvbGRfc2l6ZSldKSkNCg0KDQojVmlzdWFsaXphdGlvbg0Kc3BlbmRpbmdfcGxvdCA8LSBnZ3Bsb3QoaG91c2Vob2xkX3NwZW5kaW5nLCBhZXMoeCA9IGhvdXNlaG9sZF9jb21wLCB5ID0gYXZlcmFnZV9zcGVuZGluZykpICsNCiAgZ2VvbV9jb2woZmlsbCA9ICJncmV5ODAiLCBjb2xvciA9ICJibGFjayIpICsgIA0KICBnZW9tX3BvaW50KGFlcyh5ID0gYXZlcmFnZV9zcGVuZGluZyksIGNvbG9yID0gInJlZCIsIHNpemUgPSAzLCBzaG93LmxlZ2VuZCA9IEZBTFNFKSArICANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKGF2ZXJhZ2Vfc3BlbmRpbmcsIDIpKSwgdmp1c3QgPSAtMiwgY29sb3IgPSAiYmxhY2siKSArICANCiAgbGFicyh0aXRsZSA9ICJBdmVyYWdlIEhvdXNlaG9sZCBTcGVuZGluZyBieSBDb21wb3NpdGlvbiIsDQogICAgICAgeCA9ICJIb3VzZWhvbGQgQ29tcG9zaXRpb24iLA0KICAgICAgIHkgPSAiQXZlcmFnZSBTcGVuZGluZyAoJCkiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKA0KICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgaGp1c3QgPSAwLjUsIHNpemUgPSAxNiksDQogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTIpLA0KICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgdmp1c3QgPSAxKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChjb2xvciA9ICJibGFjayIpLA0KICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJncmV5NTAiKSwgICMgDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfbGluZShjb2xvciA9ICJncmV5OTAiKSwgIA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCkgIA0KICApDQpwcmludChzcGVuZGluZ19wbG90KQ0KYGBgDQpDb3Vwb24gVXNhZ2UgQmV0d2VlbiBIb3VzZWhvbGRzIFdpdGggYW5kIFdpdGhvdXQgQ2hpbGRyZW4NCmBgYHtyfQ0KI0ZpbHRlcg0KZGVtb2dyYXBoaWNzJGhhc19jaGlsZHJlbiA8LSBpZmVsc2UoZGVtb2dyYXBoaWNzJGtpZHNfY291bnQgPiAwLCAiV2l0aCBDaGlsZHJlbiIsICJObyBDaGlsZHJlbiIpDQoNCiMgTWVyZ2UNCmhvdXNlaG9sZF9jb3Vwb25zIDwtIGNvdXBvbl9yZWRlbXB0aW9ucyAlPiUNCiAgaW5uZXJfam9pbihkZW1vZ3JhcGhpY3MsIGJ5ID0gImhvdXNlaG9sZF9pZCIpICU+JQ0KICBncm91cF9ieShoYXNfY2hpbGRyZW4pICU+JQ0KICBzdW1tYXJpemUodG90YWxfY291cG9uc191c2VkID0gbigpLCBudW1faG91c2Vob2xkcyA9IG5fZGlzdGluY3QoaG91c2Vob2xkX2lkKSwgLmdyb3VwcyA9ICdkcm9wJykgJT4lDQogIG11dGF0ZShhdmVyYWdlX2NvdXBvbnNfcGVyX2hvdXNlaG9sZCA9IHRvdGFsX2NvdXBvbnNfdXNlZCAvIG51bV9ob3VzZWhvbGRzKQ0KI1Zpc3VhbGl6YXRpb24NCmNvbG9yc19mb3JfY2hpbGRyZW5fc3RhdHVzIDwtIGMoIldpdGggQ2hpbGRyZW4iID0gIiM1NkI0RTkiLCAiTm8gQ2hpbGRyZW4iID0gIiNFNjlGMDAiKQ0KDQpjb3Vwb25fdXNhZ2VfcGxvdCA8LSBnZ3Bsb3QoaG91c2Vob2xkX2NvdXBvbnMsIGFlcyh4ID0gaGFzX2NoaWxkcmVuLCB5ID0gYXZlcmFnZV9jb3Vwb25zX3Blcl9ob3VzZWhvbGQsIGZpbGwgPSBoYXNfY2hpbGRyZW4pKSArDQogIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsgIA0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2xvcnNfZm9yX2NoaWxkcmVuX3N0YXR1cykgKyANCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IHJvdW5kKGF2ZXJhZ2VfY291cG9uc19wZXJfaG91c2Vob2xkLCAyKSksIHZqdXN0ID0gLTAuNSwgY29sb3IgPSAid2hpdGUiKSArIA0KICBsYWJzKHRpdGxlID0gIkF2ZXJhZ2UgQ291cG9uIFVzYWdlIHBlciBIb3VzZWhvbGQgYnkgQ2hpbGQgU3RhdHVzIiwNCiAgICAgICB4ID0gIkhvdXNlaG9sZCBDaGlsZCBTdGF0dXMiLA0KICAgICAgIHkgPSAiQXZlcmFnZSBDb3Vwb25zIFVzZWQgcGVyIEhvdXNlaG9sZCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoDQogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBoanVzdCA9IDAuNSwgc2l6ZSA9IDE2KSwNCiAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxMiksDQogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCBoanVzdCA9IDAuNSksDQogICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoY29sb3IgPSAiYmxhY2siKSwNCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiZ3JleTUwIiksICANCiAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk5MCIpLCAgDQogICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSAgDQogICkNCg0KcHJpbnQoY291cG9uX3VzYWdlX3Bsb3QpDQoNCmBgYA0KDQo=