Objective: Mine Customer Purchase History for Similarity to Other “Like” Customers

bike_orderlines_tbl <- read_rds("../00_data/bike_sales/data_wrangled/bike_orderlines.rds")

kable(head(bike_orderlines_tbl,10))
order_date order_id order_line quantity price total_price model category_1 category_2 frame_material bikeshop_name city state
2011-01-07 1 1 1 6070 6070 Jekyll Carbon 2 Mountain Over Mountain Carbon Ithaca Mountain Climbers Ithaca NY
2011-01-07 1 2 1 5970 5970 Trigger Carbon 2 Mountain Over Mountain Carbon Ithaca Mountain Climbers Ithaca NY
2011-01-10 2 1 1 2770 2770 Beast of the East 1 Mountain Trail Aluminum Kansas City 29ers Kansas City KS
2011-01-10 2 2 1 5970 5970 Trigger Carbon 2 Mountain Over Mountain Carbon Kansas City 29ers Kansas City KS
2011-01-10 3 1 1 10660 10660 Supersix Evo Hi-Mod Team Road Elite Road Carbon Louisville Race Equipment Louisville KY
2011-01-10 3 2 1 3200 3200 Jekyll Carbon 4 Mountain Over Mountain Carbon Louisville Race Equipment Louisville KY
2011-01-10 3 3 1 12790 12790 Supersix Evo Black Inc. Road Elite Road Carbon Louisville Race Equipment Louisville KY
2011-01-10 3 4 1 5330 5330 Supersix Evo Hi-Mod Dura Ace 2 Road Elite Road Carbon Louisville Race Equipment Louisville KY
2011-01-10 3 5 1 1570 1570 Synapse Disc 105 Road Endurance Road Aluminum Louisville Race Equipment Louisville KY
2011-01-11 4 1 1 4800 4800 Synapse Carbon Disc Ultegra D12 Road Endurance Road Carbon Ann Arbor Speed Ann Arbor MI

Step 1 - Aggregate, Normalize/Standardize Data

customer_trends_tbl <- bike_orderlines_tbl %>%
    select(bikeshop_name, price, model, category_1, category_2, frame_material, quantity) %>% 
    
    group_by(bikeshop_name, price, model, category_1, category_2, frame_material) %>% 
 
    summarize(quantity_purchased = sum(quantity)) %>% 
    
    ungroup() %>% 
    
    # Normalization
    
    group_by(bikeshop_name) %>% 
    mutate(prop_of_total = quantity_purchased / sum(quantity_purchased)) %>% 
    ungroup()

kable(head(customer_trends_tbl, 10))
bikeshop_name price model category_1 category_2 frame_material quantity_purchased prop_of_total
Albuquerque Cycles 415 Catalyst 4 Mountain Sport Aluminum 5 0.0174825
Albuquerque Cycles 480 Catalyst 3 Mountain Sport Aluminum 9 0.0314685
Albuquerque Cycles 585 Catalyst 2 Mountain Sport Aluminum 4 0.0139860
Albuquerque Cycles 705 Catalyst 1 Mountain Sport Aluminum 6 0.0209790
Albuquerque Cycles 815 CAAD8 Claris Road Elite Road Aluminum 2 0.0069930
Albuquerque Cycles 815 Trail 5 Mountain Sport Aluminum 3 0.0104895
Albuquerque Cycles 870 Synapse Claris Road Endurance Road Aluminum 3 0.0104895
Albuquerque Cycles 980 Trail 4 Mountain Sport Aluminum 5 0.0174825
Albuquerque Cycles 1030 CAAD8 Sora Road Elite Road Aluminum 2 0.0069930
Albuquerque Cycles 1080 Trail 3 Mountain Sport Aluminum 2 0.0069930

Step 2: Convert to User-Item Format

customer_product_tbl <- customer_trends_tbl %>%
    select(bikeshop_name, model, prop_of_total) %>% 
    spread(key = model, value = prop_of_total, fill = 0)

kable(head(customer_product_tbl, 10))
bikeshop_name Bad Habit 1 Bad Habit 2 Beast of the East 1 Beast of the East 2 Beast of the East 3 CAAD Disc Ultegra CAAD12 105 CAAD12 Black Inc CAAD12 Disc 105 CAAD12 Disc Dura Ace CAAD12 Red CAAD12 Ultegra CAAD8 105 CAAD8 Claris CAAD8 Sora CAAD8 Tiagra Catalyst 1 Catalyst 2 Catalyst 3 Catalyst 4 F-Si 1 F-Si 2 F-Si 3 F-Si Black Inc. F-Si Carbon 2 F-Si Carbon 4 F-Si Hi-Mod 1 F-Si Hi-Mod Team Fat CAAD1 Fat CAAD2 Habit 4 Habit 5 Habit 6 Habit Carbon 1 Habit Carbon 2 Habit Carbon 3 Habit Carbon SE Habit Hi-Mod Black Inc. Jekyll Carbon 1 Jekyll Carbon 2 Jekyll Carbon 3 Jekyll Carbon 4 Scalpel-Si 5 Scalpel-Si Black Inc. Scalpel-Si Carbon 2 Scalpel-Si Carbon 3 Scalpel-Si Carbon 4 Scalpel-Si Hi-Mod 1 Scalpel-Si Race Scalpel 29 4 Scalpel 29 Carbon 2 Scalpel 29 Carbon 3 Scalpel 29 Carbon Race Slice 105 Slice Hi-Mod Black Inc. Slice Hi-Mod Dura Ace D12 Slice Ultegra Slice Ultegra D12 Supersix Evo 105 Supersix Evo Black Inc. Supersix Evo Hi-Mod Dura Ace 1 Supersix Evo Hi-Mod Dura Ace 2 Supersix Evo Hi-Mod Team Supersix Evo Hi-Mod Utegra Supersix Evo Red Supersix Evo Tiagra Supersix Evo Ultegra 3 Supersix Evo Ultegra 4 SuperX 105 SuperX Hi-Mod CX1 SuperX Rival CX1 SuperX Ultegra Syapse Carbon Tiagra Synapse Carbon 105 Synapse Carbon Disc 105 Synapse Carbon Disc Ultegra Synapse Carbon Disc Ultegra D12 Synapse Carbon Ultegra 3 Synapse Carbon Ultegra 4 Synapse Claris Synapse Disc 105 Synapse Disc Adventure Synapse Disc Tiagra Synapse Hi-Mod Disc Black Inc. Synapse Hi-Mod Disc Red Synapse Hi-Mod Disc Ultegra Synapse Hi-Mod Dura Ace Synapse Sora Trail 1 Trail 2 Trail 3 Trail 4 Trail 5 Trigger Carbon 1 Trigger Carbon 2 Trigger Carbon 3 Trigger Carbon 4
Albuquerque Cycles 0.0174825 0.0069930 0.0104895 0.0104895 0.0034965 0.0139860 0.0069930 0.0000000 0.0139860 0.0489510 0.0139860 0.0139860 0.0279720 0.0069930 0.0069930 0.0104895 0.0209790 0.0139860 0.0314685 0.0174825 0.0104895 0.0174825 0.0174825 0.0000000 0.0174825 0.0104895 0.0034965 0.0069930 0.0139860 0.0174825 0.0209790 0.0174825 0.0104895 0.0034965 0.0034965 0.0000000 0.0000000 0.0279720 0.0104895 0.0000000 0.0000000 0.0104895 0.0034965 0.0034965 0.0000000 0.0034965 0.0069930 0.0034965 0.0419580 0.0104895 0.0069930 0.0034965 0.0000000 0.0139860 0.0034965 0.0069930 0.0104895 0.0104895 0.0104895 0.0069930 0.0000000 0.0174825 0.0034965 0.0069930 0.0069930 0.0104895 0.0069930 0.0069930 0.0139860 0.0034965 0.0069930 0.0000000 0.0209790 0.0209790 0.0139860 0.0069930 0.0034965 0.0104895 0.0104895 0.0104895 0.0279720 0.0069930 0.0174825 0.0000000 0.0244755 0.0104895 0.0034965 0.0000000 0.0000000 0.0034965 0.0069930 0.0174825 0.0104895 0.0069930 0.0034965 0.0069930 0.0069930
Ann Arbor Speed 0.0066445 0.0099668 0.0149502 0.0099668 0.0033223 0.0265781 0.0149502 0.0166113 0.0149502 0.0083056 0.0265781 0.0132890 0.0232558 0.0149502 0.0182724 0.0116279 0.0066445 0.0083056 0.0066445 0.0049834 0.0016611 0.0033223 0.0099668 0.0000000 0.0016611 0.0099668 0.0000000 0.0000000 0.0016611 0.0049834 0.0049834 0.0066445 0.0083056 0.0000000 0.0000000 0.0016611 0.0033223 0.0016611 0.0000000 0.0016611 0.0033223 0.0149502 0.0066445 0.0016611 0.0000000 0.0000000 0.0016611 0.0000000 0.0016611 0.0099668 0.0016611 0.0000000 0.0033223 0.0232558 0.0116279 0.0132890 0.0132890 0.0265781 0.0199336 0.0215947 0.0132890 0.0083056 0.0332226 0.0083056 0.0282392 0.0149502 0.0132890 0.0199336 0.0116279 0.0066445 0.0232558 0.0249169 0.0299003 0.0215947 0.0166113 0.0083056 0.0166113 0.0083056 0.0182724 0.0332226 0.0116279 0.0083056 0.0132890 0.0049834 0.0083056 0.0132890 0.0132890 0.0099668 0.0099668 0.0149502 0.0099668 0.0033223 0.0116279 0.0000000 0.0000000 0.0000000 0.0116279
Austin Cruisers 0.0081301 0.0040650 0.0081301 0.0081301 0.0000000 0.0203252 0.0203252 0.0040650 0.0243902 0.0081301 0.0162602 0.0325203 0.0121951 0.0284553 0.0121951 0.0162602 0.0121951 0.0081301 0.0040650 0.0284553 0.0121951 0.0081301 0.0040650 0.0000000 0.0040650 0.0162602 0.0000000 0.0040650 0.0040650 0.0040650 0.0040650 0.0040650 0.0243902 0.0000000 0.0000000 0.0000000 0.0040650 0.0000000 0.0000000 0.0000000 0.0000000 0.0040650 0.0162602 0.0040650 0.0040650 0.0000000 0.0000000 0.0000000 0.0000000 0.0081301 0.0000000 0.0040650 0.0000000 0.0203252 0.0121951 0.0081301 0.0406504 0.0121951 0.0121951 0.0081301 0.0040650 0.0040650 0.0121951 0.0203252 0.0243902 0.0040650 0.0528455 0.0365854 0.0243902 0.0081301 0.0000000 0.0040650 0.0162602 0.0162602 0.0121951 0.0000000 0.0000000 0.0203252 0.0203252 0.0081301 0.0203252 0.0040650 0.0284553 0.0040650 0.0162602 0.0040650 0.0081301 0.0203252 0.0162602 0.0162602 0.0162602 0.0081301 0.0081301 0.0000000 0.0000000 0.0000000 0.0162602
Cincinnati Speed 0.0051151 0.0000000 0.0000000 0.0000000 0.0000000 0.0153453 0.0102302 0.0153453 0.0076726 0.0179028 0.0281330 0.0076726 0.0153453 0.0076726 0.0255754 0.0025575 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0025575 0.0025575 0.0076726 0.0076726 0.0000000 0.0230179 0.0076726 0.0025575 0.0000000 0.0000000 0.0025575 0.0000000 0.0051151 0.0102302 0.0076726 0.0102302 0.0204604 0.0051151 0.0051151 0.0051151 0.0076726 0.0076726 0.0153453 0.0076726 0.0127877 0.0102302 0.0127877 0.0025575 0.0051151 0.0153453 0.0025575 0.0102302 0.0204604 0.0179028 0.0204604 0.0179028 0.0179028 0.0076726 0.0306905 0.0076726 0.0102302 0.0179028 0.0230179 0.0153453 0.0153453 0.0255754 0.0025575 0.0127877 0.0255754 0.0102302 0.0127877 0.0051151 0.0076726 0.0127877 0.0332481 0.0179028 0.0127877 0.0076726 0.0102302 0.0102302 0.0127877 0.0127877 0.0255754 0.0153453 0.0230179 0.0179028 0.0127877 0.0000000 0.0025575 0.0025575 0.0025575 0.0000000 0.0102302 0.0076726 0.0102302 0.0204604
Columbus Race Equipment 0.0101523 0.0000000 0.0000000 0.0050761 0.0025381 0.0101523 0.0279188 0.0279188 0.0253807 0.0126904 0.0177665 0.0177665 0.0152284 0.0025381 0.0076142 0.0101523 0.0000000 0.0025381 0.0000000 0.0025381 0.0000000 0.0000000 0.0076142 0.0050761 0.0126904 0.0025381 0.0050761 0.0126904 0.0076142 0.0000000 0.0000000 0.0000000 0.0025381 0.0101523 0.0050761 0.0228426 0.0076142 0.0101523 0.0050761 0.0076142 0.0177665 0.0126904 0.0076142 0.0126904 0.0025381 0.0126904 0.0152284 0.0126904 0.0380711 0.0126904 0.0076142 0.0050761 0.0076142 0.0025381 0.0228426 0.0126904 0.0203046 0.0203046 0.0101523 0.0025381 0.0101523 0.0101523 0.0076142 0.0126904 0.0126904 0.0101523 0.0253807 0.0000000 0.0050761 0.0152284 0.0050761 0.0203046 0.0101523 0.0126904 0.0101523 0.0279188 0.0228426 0.0025381 0.0126904 0.0101523 0.0101523 0.0050761 0.0076142 0.0203046 0.0152284 0.0177665 0.0380711 0.0152284 0.0025381 0.0025381 0.0050761 0.0000000 0.0000000 0.0101523 0.0050761 0.0177665 0.0050761
Dallas Cycles 0.0128205 0.0170940 0.0042735 0.0042735 0.0042735 0.0000000 0.0299145 0.0042735 0.0085470 0.0085470 0.0299145 0.0000000 0.0128205 0.0042735 0.0213675 0.0000000 0.0213675 0.0128205 0.0427350 0.0170940 0.0042735 0.0256410 0.0085470 0.0128205 0.0042735 0.0128205 0.0000000 0.0042735 0.0000000 0.0128205 0.0128205 0.0085470 0.0128205 0.0000000 0.0000000 0.0170940 0.0000000 0.0000000 0.0042735 0.0042735 0.0042735 0.0128205 0.0085470 0.0128205 0.0000000 0.0000000 0.0000000 0.0042735 0.0085470 0.0128205 0.0299145 0.0170940 0.0085470 0.0128205 0.0000000 0.0085470 0.0085470 0.0128205 0.0299145 0.0000000 0.0000000 0.0042735 0.0170940 0.0085470 0.0000000 0.0000000 0.0256410 0.0042735 0.0128205 0.0000000 0.0299145 0.0042735 0.0042735 0.0170940 0.0170940 0.0128205 0.0042735 0.0213675 0.0042735 0.0256410 0.0213675 0.0128205 0.0128205 0.0000000 0.0042735 0.0000000 0.0042735 0.0213675 0.0170940 0.0085470 0.0256410 0.0128205 0.0299145 0.0042735 0.0042735 0.0042735 0.0085470
Denver Bike Shop 0.0117340 0.0139070 0.0182529 0.0152108 0.0169492 0.0108648 0.0134724 0.0030422 0.0073881 0.0017384 0.0095611 0.0139070 0.0086919 0.0091265 0.0108648 0.0065189 0.0169492 0.0256410 0.0165146 0.0199913 0.0204259 0.0182529 0.0108648 0.0108648 0.0095611 0.0165146 0.0073881 0.0108648 0.0095611 0.0178183 0.0165146 0.0139070 0.0221643 0.0134724 0.0073881 0.0095611 0.0078227 0.0117340 0.0104302 0.0086919 0.0091265 0.0147762 0.0130378 0.0112994 0.0160800 0.0104302 0.0073881 0.0130378 0.0082573 0.0186875 0.0104302 0.0121686 0.0130378 0.0056497 0.0013038 0.0008692 0.0095611 0.0134724 0.0095611 0.0013038 0.0021730 0.0013038 0.0008692 0.0008692 0.0026076 0.0086919 0.0082573 0.0086919 0.0126032 0.0021730 0.0091265 0.0126032 0.0082573 0.0091265 0.0065189 0.0021730 0.0021730 0.0078227 0.0069535 0.0073881 0.0082573 0.0056497 0.0112994 0.0013038 0.0021730 0.0013038 0.0004346 0.0069535 0.0204259 0.0208605 0.0126032 0.0152108 0.0204259 0.0121686 0.0117340 0.0126032 0.0126032
Detroit Cycles 0.0099206 0.0158730 0.0119048 0.0059524 0.0119048 0.0079365 0.0277778 0.0138889 0.0297619 0.0059524 0.0198413 0.0059524 0.0218254 0.0059524 0.0099206 0.0138889 0.0059524 0.0079365 0.0178571 0.0059524 0.0178571 0.0119048 0.0079365 0.0099206 0.0119048 0.0238095 0.0000000 0.0079365 0.0039683 0.0059524 0.0099206 0.0138889 0.0178571 0.0019841 0.0039683 0.0059524 0.0019841 0.0039683 0.0138889 0.0059524 0.0099206 0.0099206 0.0099206 0.0019841 0.0039683 0.0059524 0.0039683 0.0000000 0.0218254 0.0138889 0.0099206 0.0059524 0.0039683 0.0178571 0.0079365 0.0019841 0.0099206 0.0178571 0.0138889 0.0039683 0.0000000 0.0079365 0.0000000 0.0019841 0.0019841 0.0178571 0.0059524 0.0079365 0.0059524 0.0099206 0.0297619 0.0178571 0.0198413 0.0079365 0.0099206 0.0000000 0.0099206 0.0099206 0.0119048 0.0099206 0.0019841 0.0138889 0.0218254 0.0039683 0.0099206 0.0019841 0.0218254 0.0218254 0.0099206 0.0079365 0.0119048 0.0079365 0.0198413 0.0178571 0.0039683 0.0158730 0.0099206
Indianapolis Velocipedes 0.0062696 0.0031348 0.0094044 0.0094044 0.0000000 0.0094044 0.0094044 0.0156740 0.0094044 0.0000000 0.0501567 0.0219436 0.0094044 0.0156740 0.0156740 0.0344828 0.0125392 0.0094044 0.0125392 0.0250784 0.0094044 0.0407524 0.0000000 0.0000000 0.0062696 0.0000000 0.0000000 0.0000000 0.0062696 0.0062696 0.0031348 0.0062696 0.0000000 0.0000000 0.0031348 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0000000 0.0062696 0.0125392 0.0000000 0.0062696 0.0000000 0.0031348 0.0000000 0.0000000 0.0188088 0.0000000 0.0062696 0.0000000 0.0031348 0.0156740 0.0188088 0.0094044 0.0125392 0.0282132 0.0282132 0.0062696 0.0094044 0.0031348 0.0156740 0.0344828 0.0125392 0.0188088 0.0282132 0.0125392 0.0156740 0.0062696 0.0031348 0.0313480 0.0156740 0.0094044 0.0062696 0.0062696 0.0062696 0.0376176 0.0188088 0.0282132 0.0125392 0.0407524 0.0031348 0.0094044 0.0062696 0.0031348 0.0062696 0.0188088 0.0094044 0.0125392 0.0125392 0.0031348 0.0031348 0.0031348 0.0000000 0.0000000
Ithaca Mountain Climbers 0.0181962 0.0110759 0.0213608 0.0181962 0.0102848 0.0000000 0.0015823 0.0071203 0.0007911 0.0079114 0.0134494 0.0007911 0.0015823 0.0015823 0.0000000 0.0031646 0.0071203 0.0047468 0.0047468 0.0055380 0.0181962 0.0110759 0.0094937 0.0166139 0.0189873 0.0063291 0.0166139 0.0197785 0.0150316 0.0047468 0.0023734 0.0079114 0.0047468 0.0197785 0.0197785 0.0118671 0.0221519 0.0142405 0.0276899 0.0181962 0.0142405 0.0237342 0.0134494 0.0237342 0.0181962 0.0237342 0.0197785 0.0118671 0.0134494 0.0142405 0.0110759 0.0158228 0.0174051 0.0000000 0.0023734 0.0079114 0.0000000 0.0229430 0.0000000 0.0118671 0.0094937 0.0110759 0.0134494 0.0055380 0.0110759 0.0007911 0.0102848 0.0015823 0.0000000 0.0181962 0.0000000 0.0007911 0.0000000 0.0015823 0.0007911 0.0110759 0.0126582 0.0079114 0.0000000 0.0007911 0.0023734 0.0023734 0.0007911 0.0142405 0.0094937 0.0055380 0.0094937 0.0015823 0.0087025 0.0221519 0.0110759 0.0166139 0.0055380 0.0181962 0.0229430 0.0261076 0.0150316

Step 3: Perform K-Means Clustering Analysis

kmeans_obj <- customer_product_tbl %>% 
    # Exlude non-numeric columns 
    select(-bikeshop_name) %>%
    # Centers indicates how many centers/groups K-Means Algorithm should look for.
    # NStart - KM picks a random starting point and then interatively finds the best location for the centers; default = 1.
    kmeans(centers = 3, nstart = 100)
kmeans_obj %>% glance()
# Classification of Clusters
kmeans_obj$cluster
##  [1] 1 1 1 2 2 1 1 1 1 3 1 2 1 2 1 1 1 1 1 1 1 1 3 1 1 1 2 1 3 2
# A Look at Broom's Functionality

broom::tidy(kmeans_obj)
broom::glance(kmeans_obj)
# Quick Look at Cluster Assignment
broom::augment(kmeans_obj, customer_product_tbl) %>% 
    select(bikeshop_name, .cluster)

Step 4: Determine Final Number of Centers to Use aka Optimal Value for K

# Create function that can be iterated...

# Functions that works on 1 element
center <- 3

kmeans_mapper <- function(centers = 3) {
    
    customer_product_tbl %>%
        select(-bikeshop_name) %>%
        kmeans(centers = centers, nstart = 100)
}

3 %>% kmeans_mapper() %>% glance()
# Mapping the function to many elements
kmeans_mapped_tbl <- tibble(centers = 1:15) %>%
    mutate(k_means = centers %>% map(kmeans_mapper)) %>%
    mutate(glance  = k_means %>% map(glance))

kmeans_mapped_tbl %>%
    unnest(glance) %>%
    select(centers, tot.withinss) %>% 
    
    # Scree Plot - Optimal Number of Clusters Appears to be 4
    
    ggplot(aes(x = centers, y = tot.withinss)) +
    geom_point() +
    geom_point(color = "#2c3e50", size = 1) +
    geom_line(color = "#2c3e50", size = 1) +
    labs(title = "Scree Plot",
         caption = "Based on Scree Plot, Optimal Number of Clusters is Four (4)") +
    theme_tq() +
    ggrepel::geom_label_repel(aes(label = centers))

Step 5: Apply UMAP to customer_product_tbl, then combine layout from umap_results with bikeshop_name from stock_data_matrix_tbl and visualize.

umap_results <- customer_product_tbl %>% 
    select(-bikeshop_name) %>% 
    umap()


umap_results_tbl <- umap_results$layout %>% 
    as_tibble() %>% 
    bind_cols(customer_product_tbl %>% select(bikeshop_name))
    
# Build UMAP Results Plot
umap_results_tbl %>% 
    ggplot(aes(x = V1, y = V2)) +
    geom_point(alpha = 0.5) +
    theme_tq() +
    labs(title = "UMAP Results") +
    ggrepel::geom_label_repel(aes(label = bikeshop_name), size = 2)

Step 6: Use K-Means to Add Cluster Assignments In

umap_results_tbl
kmeans_4_obj <- kmeans_mapped_tbl %>%
    pull(k_means) %>%
    pluck(4)

kmeans_4_clusters_tbl <- kmeans_4_obj %>% 
    augment(customer_product_tbl) %>%
    select(bikeshop_name, .cluster)

umap_kmeans_4_results_tbl <- umap_results_tbl %>%
    left_join(kmeans_4_clusters_tbl)

Step 7: Visualize UMAP’d Projections with Cluster Assignments

umap_kmeans_4_results_tbl %>%
    mutate(label_text = str_glue("Customer: {bikeshop_name}.
                                 Cluster: {.cluster}")) %>% 
    
    ggplot(aes(x = V1, y = V2, color = .cluster)) +
    geom_point(alpha = 1) +
    theme_tq() +
    scale_color_tq() +
    ggrepel::geom_label_repel(aes(label = label_text), size = 2) +
    labs(
        title = "Customer Segmentation: 2D Projection",
        subtitle = "UMAP 2D Projection with K-Means Cluster Assignment",
        caption = "Conclusion: Four Customer Segments Identified Using K-Means and UMAP Algorithms"
    ) +
    theme(legend.position = "none")