<jupyter_start><jupyter_text>Environment Setup<jupyter_code># import and install all required libraries
import pandas as pd
import seaborn as sns
import datetime as dt
import matplotlib.pyplot as plt
import numpy as np

! pip install lifetimes==0.11.3
from lifetimes.plotting import *
from lifetimes.utils import *
from lifetimes import BetaGeoFitter
from lifetimes import GammaGammaFitter
# Load data
data = pd.read_csv('.../OnlineRetail_2yrs.csv')<jupyter_output><empty_output><jupyter_text>EDA and Data Preprocessing<jupyter_code>data.head(10)
data.info()
# Convert InvoiceDate into DateTime format and extract the date values
data['InvoiceDate'] = pd.to_datetime(data['InvoiceDate']).dt.date
# drop rows with missing CustomerID as our analysis will be at the individual customer level
data.dropna(axis = 0, subset = ['Customer ID'], inplace = True)
# filter out the negative values from Quantity field as these could relate to returns that are not relevant to LTV predictions
data = data[(data['Quantity'] > 0)]
# create a new column for Sales per invoice and filter out only the required columns for the Lifetimes package
data['Sales'] = data['Quantity'] * data['Price']
data_final = data[['Customer ID', 'InvoiceDate', 'Sales']]
data_final.head()
data_final.info()
# transform our transaction level data into the required summary form for Lifetimes
data_summary = summary_data_from_transaction_data(data_final, customer_id_col = 'Customer ID', datetime_col = 'InvoiceDate', monetary_value_col = 'Sales', freq = 'D')
# used freq = 'D' since we have a daily transactions log
data_summary.head(10)
# retain only those customers with frequency > 0
data_summary = data_summary[data_summary['frequency'] > 0]
# Some descriptive statistics of the summary data
data_summary.describe()<jupyter_output><empty_output><jupyter_text>BG/NBD Model Training & Visualisation<jupyter_code># fit the BG/NBD model to our data_summary
bgf = BetaGeoFitter()
bgf.fit(data_summary['frequency'], data_summary['recency'], data_summary['T'])
# plot the estimated gamma distribution of λ (customers' propensities to purchase)
plot_transaction_rate_heterogeneity(bgf);
# plot the estimated beta distribution of p, a customers' probability of dropping out immediately after a transaction
plot_dropout_rate_heterogeneity(bgf);
# visualize our frequency/recency matrix
fig = plt.figure(figsize=(12,8))
plot_frequency_recency_matrix(bgf, T = 7);
# Now let's visualise the probability of a customer being alive
fig = plt.figure(figsize=(12,8))
plot_probability_alive_matrix(bgf);<jupyter_output><empty_output><jupyter_text>Model Validation<jupyter_code># partition the dataset into a calibration and a holdout dataset
summary_cal_holdout = calibration_and_holdout_data(data_final, 'Customer ID', 'InvoiceDate', freq = "D", monetary_value_col = 'Sales', calibration_period_end='2011-06-30')
summary_cal_holdout.head()
# again, retain only the +ve frequency_cal values
summary_cal_holdout = summary_cal_holdout[summary_cal_holdout['frequency_cal'] > 0]
# compare the predicted # of repeat puchases with actual repeat purchases during the holdout period
bgf_cal = BetaGeoFitter()
bgf_cal.fit(summary_cal_holdout['frequency_cal'], summary_cal_holdout['recency_cal'], summary_cal_holdout['T_cal'])
plot_calibration_purchases_vs_holdout_purchases(bgf_cal, summary_cal_holdout, kind = 'frequency_cal', n = int(summary_cal_holdout['frequency_holdout'].max()), figsize = (12,8));<jupyter_output><empty_output><jupyter_text>Gamma-Gamma Model Fitting<jupyter_code># Let's fit the Gamma-Gamma model to our data_summary
ggf = GammaGammaFitter()
ggf.fit(frequency = data_summary['frequency'], monetary_value = data_summary['monetary_value'])<jupyter_output><empty_output><jupyter_text>Prediction Time!<jupyter_code># Calculate the expected number of repeat purchases up to time t for a randomly chosen individual from the population
t = 30 # to calculate the number of expected repeat purchases over the next 30 days
data_summary['predicted_purchases'] = bgf.conditional_expected_number_of_purchases_up_to_time(t, data_summary['frequency'], data_summary['recency'], data_summary['T'])
data_summary.sort_values(by='predicted_purchases').tail(5)
# Calculate probability of being currently alive and assign to each CustomerID
data_summary['p_alive'] = bgf.conditional_probability_alive(data_summary['frequency'], data_summary['recency'], data_summary['T'])
data_summary.sort_values(by='predicted_purchases').tail(5)
sns.distplot(data_summary['p_alive']);
data_summary['churn'] = ['churned' if p_alive < 0.5 else 'not churned' for p_alive in data_summary['p_alive']]
data_summary['churn'][(data_summary['p_alive'] >= 0.5) & (data_summary['p_alive'] < 0.75)] = "high risk"
data_summary['churn'].value_counts()
# After applying Gamma-Gamma model, now we can estimate average transaction value for each customer over his/her lifetime
data_summary['predicted_Sales'] = ggf.conditional_expected_average_profit(data_summary['frequency'], data_summary['monetary_value'])
data_summary.head()
# Final piece of the puzzle - calculate LTV for each customer over the next 12 months with an assumed monthly discount rate of 0.01%
data_summary['LTV'] = ggf.customer_lifetime_value(
    bgf, #the model to use to predict the number of future transactions
    data_summary['frequency'], data_summary['recency'], data_summary['T'], data_summary['monetary_value'],
    time = 12, # number of months to predict LTV for
    discount_rate = 0.01 # monthly discount rate ~ 12.7% annually
)
data_summary.head()
# Let's identify our top 20 customers based on LTV
best_projected_cust_LTV = data_summary.sort_values('LTV').tail(20)
best_projected_cust_LTV<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09994748818484159, 'fraction_numerical': 0.010852441799404866, 'mean_word_length': 7.710365853658536, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 30, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '56098', 'license': 'MIT', 'n_tokens_mistral': 1815, 'n_tokens_neox': 1722, 'n_words': 502, 'path': 'LTV_Analysis.ipynb', 'repo_name': 'finlytics-hub/LTV_predictions', 'size': '5713'}