###################################################
# Chapter 9: Customer Lifetime Value (CLV)        #
# Chestnut Ridge Multi-channel Retailer Example   #
###################################################

# This script reproduces the full Chestnut Ridge customer lifetime value (CLV) example in R:
#   Step 1. Data setup (uses the output file from the Chapter 8 example)
#   Step 2. Compute CLV using P(alive) and using the logistic regression prediction
#   Step 3. CLV decile charts
#   Step 4. Manage customers using CLV (compare customer selection methods in Table 9.3)
# Run it from top to bottom. Each step prints its result to the console or Plots pane.

###################################################
# Step 1: Data Setup                              #
###################################################

## Install Packages (if needed - only installs packages that are missing)
packages <- c("dplyr", "ggplot2", "scales")
new_packages <- packages[!(packages %in% installed.packages()[, "Package"])]
if (length(new_packages) > 0) install.packages(new_packages)

## Load Packages and Set Seed
library(dplyr)
library(ggplot2)
library(scales)
set.seed(1)

## Read in CLV data (the output file from the Chapter 8 Logistic Regression example)
clv <- read.csv(file.choose()) ## Choose logit_pred.csv file

## Look at the data (see Table 9.2 for variable definitions)
head(clv)
summary(clv)


###################################################
# Step 2: Computing CLV                           #
###################################################

## Assumptions
months      <- 36    ## Observation window is 3 years (36 months)
days        <- 1095  ## Observation window is 3 years (1,095 days)
margin_rate <- 0.52  ## Average gross margin for the retailer
mkt_cost    <- 1     ## Marketing cost per customer per month
annual_d    <- 0.10  ## Annual discount rate

## Monthly discount rate: (1 + d)^(1/12) - 1
discount <- (1 + annual_d)^(1 / 12) - 1
discount  ## 0.00797

## Margin, P(alive), and the two CLV calculations for each customer
## margin:       average monthly revenue times the 52% margin, less $1 in marketing costs
## p_alive:      t^n, where t = (1095 - recency_days) / 1095 and n = number_of_orders
## clv_p_alive:  CLV using P(alive) as the retention rate
## clv_predict:  CLV using the predicted probability from the Logistic regression as the retention rate
clv <- clv %>%
  mutate(margin      = (revenue / months) * margin_rate - mkt_cost,
         p_alive     = ((days - recency_days) / days)^number_of_orders,
         clv_p_alive = margin * (1 + discount) / (1 + discount - p_alive),
         clv_predict = margin * (1 + discount) / (1 + discount - predict))

## Figure 9.2: CLV P(alive) and CLV Predict for each Customer
clv %>%
  select(customer_id, clv_p_alive, clv_predict) %>%
  mutate(across(c(clv_p_alive, clv_predict), ~ dollar(.x, accuracy = 0.01))) %>%
  head(20)

## How similar are the two CLV calculations?
cor(clv$clv_p_alive, clv$clv_predict)


###################################################
# Step 3: CLV Decile Charts                       #
###################################################

## Assign each customer to a decile (10% = lowest CLV, 100% = highest CLV).
## A customer is placed in the first decile whose cutoff (percentile) is at or above
## the customer's CLV, matching the approach in the 1st edition.
clv_decile <- function(x) {
  cutoffs <- quantile(x, probs = seq(0.1, 0.9, by = 0.1))
  factor(findInterval(x, cutoffs, left.open = TRUE) + 1, levels = 1:10,
         labels = paste0(seq(10, 100, by = 10), "%"))
}

clv <- clv %>%
  mutate(decile_p_alive = clv_decile(clv_p_alive),
         decile_predict = clv_decile(clv_predict))

## Average CLV in each decile
deciles_p_alive <- clv %>%
  group_by(decile = decile_p_alive) %>%
  summarise(customers = n(), avg_clv = mean(clv_p_alive), total_clv = sum(clv_p_alive))

deciles_predict <- clv %>%
  group_by(decile = decile_predict) %>%
  summarise(customers = n(), avg_clv = mean(clv_predict), total_clv = sum(clv_predict))

deciles_p_alive  ## Top decile averages $67.01; 80% and 90% deciles average $9.32 and $16.68
deciles_predict  ## Top decile averages $70.29; 80% and 90% deciles average $6.71 and $13.14

## Function to plot the average CLV in each decile (Figures 9.3 and 9.4)
plot_clv_deciles <- function(deciles, title) {
  ggplot(deciles, aes(x = decile, y = avg_clv)) +
    geom_col(fill = "#2C5F8A") +
    geom_text(aes(label = dollar(avg_clv, accuracy = 0.01),
                  vjust = ifelse(avg_clv >= 0, -0.5, 1.5)), size = 3.5) +
    geom_hline(yintercept = 0) +
    scale_y_continuous(labels = dollar, expand = expansion(mult = 0.1)) +
    labs(title = title, x = "CLV Decile", y = "Average CLV") +
    theme_minimal() +
    theme(panel.grid.major.x = element_blank())
}

## Figure 9.3: CLV Decile Chart Using P(alive)
plot_clv_deciles(deciles_p_alive, "Decile Chart Using P(alive)")

## Figure 9.4: CLV Decile Chart Using Predict
plot_clv_deciles(deciles_predict, "Decile Chart Using Predict")

## Share of total CLV coming from the top two deciles
deciles_p_alive %>% mutate(share = percent(total_clv / sum(total_clv), accuracy = 0.1))
deciles_predict %>% mutate(share = percent(total_clv / sum(total_clv), accuracy = 0.1))


###################################################
# Step 4: Managing Customers Using CLV            #
###################################################

## Select the top 15% (1,500) of customers by CLV Predict and by the Logistic
## regression predicted probability. Table 9.3 compares the following year's profit
## of the customers selected using RFM - sequential sort (Chapter 7), Logistic
## regression (Chapter 8), and CLV Predict (this chapter).
n_select <- round(0.15 * nrow(clv))

top_clv_predict <- clv %>% slice_max(clv_predict, n = n_select, with_ties = FALSE)
top_logistic    <- clv %>% slice_max(predict, n = n_select, with_ties = FALSE)

## How many customers do the two methods have in common?
length(intersect(top_clv_predict$customer_id, top_logistic$customer_id))

## Table 9.3: Profitability Based on Different Customer Selection Criteria
table_9_3 <- data.frame(
  "RFM - Sequential Sort" = c(204.13, 310272),
  "Logistic Regression"   = c(219.35, 329023),
  "CLV Predict"           = c(247.17, 370749),
  row.names = c("Avg. Profit", "Total Profit"), check.names = FALSE)
table_9_3

## Percentage improvement in average profit
table_9_3["Avg. Profit", "Logistic Regression"] / table_9_3["Avg. Profit", "RFM - Sequential Sort"] - 1  ## 7.46%
table_9_3["Avg. Profit", "CLV Predict"] / table_9_3["Avg. Profit", "Logistic Regression"] - 1            ## 12.68%
table_9_3["Avg. Profit", "CLV Predict"] / table_9_3["Avg. Profit", "RFM - Sequential Sort"] - 1          ## 21.08%

