本文概述
意大利经济学家帕尔托(Vilfredo Pareto)说, 这种影响的80%来自20%的原因, 这就是众所周知的80/20法则或帕累托原理。同样, 公司业务的80%来自20%的客户。公司需要确定那些顶级客户并保持与他们的关系, 以确保持续的收入。为了维持与客户的长期关系, 公司需要安排忠诚度计划, 例如折扣, 优惠, 优惠券, 奖励积分和礼物。
定位新客户比保留现有客户的成本更高, 因为你无需花费资源, 时间和精力来吸引新客户。你只需要让现有客户满意即可。业务分析师使用CLTV(客户生命周期价值)准确计算客户获取成本。 CLTV表示整个关系期间来自客户的总收入。 CLTV帮助公司专注于那些可以在将来带来更多收入的潜在客户。
在本教程中, 你将涵盖以下主题:
- 介绍
- 客户生命周期价值(CLTV)
- CLTV相关工作
- CLTV公式
- 用Python实现CLTV
- CLTV的预测模型
- 利弊
- 总结
客户生命周期价值(CLTV)
“客户生命周期价值是一个货币值, 代表客户在关系期内将给公司的收入或利润额”(来源)。 CLTV证明了与长期客户相比, 获得长期客户的意义。客户生命周期价值(CLV)可以帮助你回答有关向每家公司销售的最重要的问题:
- 如何确定最赚钱的客户?
- 公司如何提供最好的产品和最多的钱?
- 如何细分获利客户?
- 获取客户需要花费多少预算?
计算客户生命周期价值
有许多方法可用于计算CLTV。每个人对此都有自己的看法。为了计算CLTV, 我们需要客户的历史数据, 但是你将无法为新客户计算。为了解决这个问题, Business Analyst开发了机器学习模型来预测新客户的CLTV。让我们探索一些CLTV计算方法:
1)你可以通过添加给定周期中来自客户的利润/收入来进行计算。例如, 如果客户与你最近3年有关联, 则你可以将这3年中的所有利润相加。你可以平均每年, 半年或每月平均利润, 但是采用这种方法, 你将无法为新客户建立预测模型。
2)为现有客户建立回归模型。将最近的六个月数据作为自变量, 将三年内的总收入作为因变量, 然后根据此数据建立回归模型。
3)CLTV还可以使用RFM(频率, 频率, 货币)值来实现。有关更多详细信息, 请参阅我的教程。
4)使用以下等式:CLTV =((平均订单价值x购买频率)/流失率)x利润率。
Customer Value = Average Order Value * Purchase Frequency
平均订单价值(AOV):”平均订单价值”是你的总收入与订单总数之比。 AOV表示客户在订单上花费的平均收入金额。
Average Order Value = Total Revenue / Total Number of Orders
购买频率(PF):购买频率是订单总数与客户总数之比。它代表每个客户下的平均订单数。
Purchase Frequency = Total Number of Orders / Total Number of Customers
客户流失率:客户流失率是没有再次下订单的客户所占的百分比。
客户生命周期:客户生命周期是客户连续订购的时间段。
Customer Lifetime=1/Churn Rate
重复率:重复率可以定义为一个以上订单的客户数量与唯一客户数量之比。示例:如果你一个月内有10位客户中有4位回来, 那么你的重复率是40%。
Churn Rate= 1-Repeat Rate
使用Python的CLTV实现(使用公式)
导入所需的库
#import modules
import pandas as pd # for dataframes
import matplotlib.pyplot as plt # for plotting graphs
import seaborn as sns # for plotting graphs
import datetime as dt
import numpy as np
加载数据集
首先, 我们使用熊猫读取CSV函数加载所需的在线零售数据集。你可以从此处下载数据。
data = pd.read_excel("Online_Retail.xlsx")
data.head()
发票号码 | 股票代码 | 描述 | 数量 | 发票日期 | 单价 | 顾客ID | 国家 | |
---|---|---|---|---|---|---|---|---|
0 | 536365 | 85123A | 白吊心T型灯架 | 6 | 2010-12-01 08:26:00 | 2.55 | 17850.0 | 英国 |
1 | 536365 | 71053 | 白金属灯笼 | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | 英国 |
2 | 536365 | 84406B | 乳白色心形衣架 | 8 | 2010-12-01 08:26:00 | 2.75 | 17850.0 | 英国 |
3 | 536365 | 84029G | 针织旗式热水瓶 | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | 英国 |
4 | 536365 | 84029E | 红色羊毛羊毛白心。 | 6 | 2010-12-01 08:26:00 | 3.39 | 17850.0 | 英国 |
删除重复项
有时你会得到一个混乱的数据集。你可能需要处理重复项, 这会使你的分析失真。在python中, 熊猫提供了drop_duplicates()函数, 该函数删除重复或重复的记录。
filtered_data=data[['Country', 'CustomerID']].drop_duplicates()
让我们进入数据洞察
#Top ten country's customer
filtered_data.Country.value_counts()[:10].plot(kind='bar')
<matplotlib.axes._subplots.AxesSubplot at 0x7fe677a887f0>
在给定的数据集中, 你可以观察到大多数客户来自”英国”。因此, 你可以为英国客户过滤数据。
uk_data=data[data.Country=='United Kingdom']
uk_data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 495478 entries, 0 to 541893
Data columns (total 8 columns):
InvoiceNo 495478 non-null object
StockCode 495478 non-null object
Description 494024 non-null object
Quantity 495478 non-null int64
InvoiceDate 495478 non-null datetime64[ns]
UnitPrice 495478 non-null float64
CustomerID 361878 non-null float64
Country 495478 non-null object
dtypes: datetime64[ns](1), float64(2), int64(1), object(4)
memory usage: 34.0+ MB
熊猫中的describe()函数可方便地获取各种摘要统计信息。此函数返回计数, 均值, 标准偏差, 最小值和最大值以及数据的分位数。
uk_data.describe()
数量 | 单价 | 顾客ID | |
---|---|---|---|
计数 | 495478.000000 | 495478.000000 | 361878.000000 |
意思 | 8.605486 | 4.532422 | 15547.871368 |
小时 | 227.588756 | 99.315438 | 1594.402590 |
我 | -80995.000000 | -11062.060000 | 12346.000000 |
25% | 1.000000 | 1.250000 | 14194.000000 |
50% | 3.000000 | 2.100000 | 15514.000000 |
75% | 10.000000 | 4.130000 | 16931.000000 |
最大值 | 80995.000000 | 38970.000000 | 18287.000000 |
在这里, 你可以观察到某些客户的订购量为负数, 这是不可能的。因此, 你需要过滤数量大于零的数量。
uk_data = uk_data[(uk_data['Quantity']>0)]
uk_data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 486286 entries, 0 to 541893
Data columns (total 8 columns):
InvoiceNo 486286 non-null object
StockCode 486286 non-null object
Description 485694 non-null object
Quantity 486286 non-null int64
InvoiceDate 486286 non-null datetime64[ns]
UnitPrice 486286 non-null float64
CustomerID 354345 non-null float64
Country 486286 non-null object
dtypes: datetime64[ns](1), float64(2), int64(1), object(4)
memory usage: 33.4+ MB
过滤所需的列
在这里, 你可以过滤用于计算CLTV的必要列。你只需要她的五个列CustomerID, InvoiceDate, InvoiceNo, Quantity和UnitPrice。
- CustomerID将唯一定义你的客户。
- InvoiceDate可帮助你计算客户使用产品的天数。
- InvoiceNo可帮助你计算执行交易的时间(频率)。
- 数量是每笔交易中的采购项目单位
- 客户购买的每个单位的单价将帮助你计算购买的总金额。
uk_data=uk_data[['CustomerID', 'InvoiceDate', 'InvoiceNo', 'Quantity', 'UnitPrice']]
#Calulate total purchase
uk_data['TotalPurchase'] = uk_data['Quantity'] * uk_data['UnitPrice']
在这里, 你将执行以下操作:
- 计算从每个客户当前日期到最后一次购买日期之间的天数。
- 计算每个客户的订单数。
- 计算每个客户的购买总价。
uk_data_group=uk_data.groupby('CustomerID').agg({'InvoiceDate': lambda date: (date.max() - date.min()).days, 'InvoiceNo': lambda num: len(num), 'Quantity': lambda quant: quant.sum(), 'TotalPurchase': lambda price: price.sum()})
uk_data_group.head()
发票日期 | 发票号码 | 数量 | TotalPurchase | |
---|---|---|---|---|
顾客ID | ||||
12346.0 | 0 | 1 | 74215 | 77183.60 |
12747.0 | 366 | 103 | 1275 | 4196.01 |
12748.0 | 372 | 4596 | 25748 | 33719.73 |
12749.0 | 209 | 199 | 1471 | 4090.88 |
12820.0 | 323 | 59 | 722 | 942.34 |
重命名列
# Change the name of columns
uk_data_group.columns=['num_days', 'num_transactions', 'num_units', 'spent_money']
uk_data_group.head()
num_days | num_transactions | NUM_UNITS | 花钱 | |
---|---|---|---|---|
顾客ID | ||||
12346.0 | 0 | 1 | 74215 | 77183.60 |
12747.0 | 366 | 103 | 1275 | 4196.01 |
12748.0 | 372 | 4596 | 25748 | 33719.73 |
12749.0 | 209 | 199 | 1471 | 4090.88 |
12820.0 | 323 | 59 | 722 | 942.34 |
使用以下公式计算CLTV:
CLTV = ((Average Order Value x Purchase Frequency)/Churn Rate) x Profit margin.
Customer Value = Average Order Value * Purchase Frequency
1.计算平均订单价值
# Average Order Value
uk_data_group['avg_order_value']=uk_data_group['spent_money']/uk_data_group['num_transactions']
uk_data_group.head()
num_days | num_transactions | NUM_UNITS | 花钱 | avg_order_value | |
---|---|---|---|---|---|
顾客ID | |||||
12346.0 | 0 | 1 | 74215 | 77183.60 | 77183.600000 |
12747.0 | 366 | 103 | 1275 | 4196.01 | 40.737961 |
12748.0 | 372 | 4596 | 25748 | 33719.73 | 7.336756 |
12749.0 | 209 | 199 | 1471 | 4090.88 | 20.557186 |
12820.0 | 323 | 59 | 722 | 942.34 | 15.971864 |
2.计算购买频率
purchase_frequency=sum(uk_data_group['num_transactions'])/uk_data_group.shape[0]
3.计算重复率和流失率
# Repeat Rate
repeat_rate=uk_data_group[uk_data_group.num_transactions > 1].shape[0]/uk_data_group.shape[0]
#Churn Rate
churn_rate=1-repeat_rate
purchase_frequency, repeat_rate, churn_rate
(90.37107880642694, 0.9818923743942872, 0.018107625605712774)
4.计算利润率
利润率是常用的获利率。它代表已赚取了总销售额的百分比。假设我们的业务在总销售额中占大约5%的利润。
# Profit Margin
uk_data_group['profit_margin']=uk_data_group['spent_money']*0.05
uk_data_group.head()
num_days | num_transactions | NUM_UNITS | 花钱 | avg_order_value | Profit_margin | |
---|---|---|---|---|---|---|
顾客ID | ||||||
12346.0 | 0 | 1 | 74215 | 77183.60 | 77183.600000 | 3859.1800 |
12747.0 | 366 | 103 | 1275 | 4196.01 | 40.737961 | 209.8005 |
12748.0 | 372 | 4596 | 25748 | 33719.73 | 7.336756 | 1685.9865 |
12749.0 | 209 | 199 | 1471 | 4090.88 | 20.557186 | 204.5440 |
12820.0 | 323 | 59 | 722 | 942.34 | 15.971864 | 47.1170 |
5.计算客户生命周期价值
# Customer Value
uk_data_group['CLV']=(uk_data_group['avg_order_value']*purchase_frequency)/churn_rate
#Customer Lifetime Value
uk_data_group['cust_lifetime_value']=uk_data_group['CLV']*uk_data_group['profit_margin']
uk_data_group.head()
num_days | num_transactions | NUM_UNITS | 花钱 | avg_order_value | Profit_margin | CLV | cust_lifetime_value | |
---|---|---|---|---|---|---|---|---|
顾客ID | ||||||||
12346.0 | 0 | 1 | 74215 | 77183.60 | 77183.600000 | 3859.1800 | 3.852060e+08 | 1.486579e+12 |
12747.0 | 366 | 103 | 1275 | 4196.01 | 40.737961 | 209.8005 | 2.033140e+05 | 4.265538e+07 |
12748.0 | 372 | 4596 | 25748 | 33719.73 | 7.336756 | 1685.9865 | 3.661610e+04 | 6.173424e+07 |
12749.0 | 209 | 199 | 1471 | 4090.88 | 20.557186 | 204.5440 | 1.025963e+05 | 2.098545e+07 |
12820.0 | 323 | 59 | 722 | 942.34 | 15.971864 | 47.1170 | 7.971198e+04 | 3.755789e+06 |
CLTV的预测模型
让我们建立CLTV预测模型。
在这里, 你将使用线性回归模型预测CLTV。
我们首先使用上面加载和过滤的数据。
uk_data.head()
顾客ID | 发票日期 | 发票号码 | 数量 | 单价 | TotalPurchase | month_yr | |
---|---|---|---|---|---|---|---|
0 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 2.55 | 15.30 | 2010年12月 |
1 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 3.39 | 20.34 | 2010年12月 |
2 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 8 | 2.75 | 22.00 | 2010年12月 |
3 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 3.39 | 20.34 | 2010年12月 |
4 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 3.39 | 20.34 | 2010年12月 |
从InvoiceDate中提取月份和年份。
uk_data['month_yr'] = uk_data['InvoiceDate'].apply(lambda x: x.strftime('%b-%Y'))
uk_data.head()
顾客ID | 发票日期 | 发票号码 | 数量 | 单价 | TotalPurchase | month_yr | |
---|---|---|---|---|---|---|---|
0 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 2.55 | 15.30 | 2010年12月 |
1 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 3.39 | 20.34 | 2010年12月 |
2 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 8 | 2.75 | 22.00 | 2010年12月 |
3 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 3.39 | 20.34 | 2010年12月 |
4 | 17850.0 | 2010-12-01 08:26:00 | 536365 | 6 | 3.39 | 20.34 | 2010年12月 |
数据透视表将这些列作为输入, 并以提供数据多维汇总的方式将条目分组为二维表。
sale=uk_data.pivot_table(index=['CustomerID'], columns=['month_yr'], values='TotalPurchase', aggfunc='sum', fill_value=0).reset_index()
sale.head()
month_yr | 顾客ID | 2011年4月 | 2011年8月 | 2010年12月 | 2011年12月 | 2011年2月 | 2011年1月 | 2011年7月 | Jun-2011 | 2011年3月 | 2011年5月 | 2011年11月 | 2011年10月 | 2011年9月 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 12346.0 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 77183.60 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 |
1 | 12747.0 | 0.00 | 301.70 | 706.27 | 438.50 | 0.00 | 303.04 | 0.00 | 376.30 | 310.78 | 771.31 | 312.73 | 675.38 | 0.00 |
2 | 12748.0 | 1100.37 | 898.24 | 4228.13 | 1070.27 | 389.64 | 418.77 | 1113.27 | 2006.26 | 1179.37 | 2234.50 | 10639.23 | 2292.84 | 6148.84 |
3 | 12749.0 | 0.00 | 1896.13 | 0.00 | 763.06 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 859.10 | 572.59 | 0.00 | 0.00 |
4 | 12820.0 | 0.00 | 0.00 | 0.00 | 210.35 | 0.00 | 170.46 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 343.76 | 217.77 |
让我们总结所有月份的销售额。
sale['CLV']=sale.iloc[:, 2:].sum(axis=1)
sale.head()
month_yr | 顾客ID | 2011年4月 | 2011年8月 | 2010年12月 | 2011年12月 | 2011年2月 | 2011年1月 | 2011年7月 | Jun-2011 | 2011年3月 | 2011年5月 | 2011年11月 | 2011年10月 | 2011年9月 | CLV |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 12346.0 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 77183.60 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 77183.60 |
1 | 12747.0 | 0.00 | 301.70 | 706.27 | 438.50 | 0.00 | 303.04 | 0.00 | 376.30 | 310.78 | 771.31 | 312.73 | 675.38 | 0.00 | 4196.01 |
2 | 12748.0 | 1100.37 | 898.24 | 4228.13 | 1070.27 | 389.64 | 418.77 | 1113.27 | 2006.26 | 1179.37 | 2234.50 | 10639.23 | 2292.84 | 6148.84 | 32619.36 |
3 | 12749.0 | 0.00 | 1896.13 | 0.00 | 763.06 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 859.10 | 572.59 | 0.00 | 0.00 | 4090.88 |
4 | 12820.0 | 0.00 | 0.00 | 0.00 | 210.35 | 0.00 | 170.46 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 343.76 | 217.77 | 942.34 |
选择特征
在这里, 你需要将给定的列分为因变量(目标变量)和自变量(或特征变量)两种类型。选择最近6个月作为自变量。
X=sale[['Dec-2011', 'Nov-2011', 'Oct-2011', 'Sep-2011', 'Aug-2011', 'Jul-2011']]
y=sale[['CLV']]
分割数据
为了了解模型的性能, 将数据集分为训练集和测试集是一个很好的策略。
让我们使用函数train_test_split()拆分数据集。你需要传递3个参数功能, 目标和test_set大小。此外, 你可以使用random_state作为种子值来保持可重复性, 这意味着每当拆分数据时都不会影响结果。另外, 如果random_state为None, 则随机数生成器使用np.random随机选择记录。这意味着如果你不设置种子, 则每次都不同。
#split training set and test set
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
模型开发
首先, 导入线性回归模块并创建一个线性回归对象。然后, 使用fit()函数将模型拟合到训练集上, 并使用predict()函数对测试集执行预测。
# import model
from sklearn.linear_model import LinearRegression
# instantiate
linreg = LinearRegression()
# fit the model to the training data (learn the coefficients)
linreg.fit(X_train, y_train)
# make predictions on the testing set
y_pred = linreg.predict(X_test)
# print the intercept and coefficients
print(linreg.intercept_)
print(linreg.coef_)
[208.50969617]
[[0.99880551 0.80381254 1.60226829 1.67433228 1.52860813 2.87959449]]
模型对数据的拟合程度如何?
为了评估线性模型的整体拟合, 我们使用R平方值。 R平方是模型解释的方差比例。 R平方的值在0到1之间。较高的值或R平方被认为更好, 因为它表示模型解释的较大方差。
from sklearn import metrics
# compute the R Square for model
print("R-Square:", metrics.r2_score(y_test, y_pred))
R-Square: 0.9666074402817512
此模型的R平方更高(0.96)。该模型可以更好地拟合数据。
模型评估
对于使用以下评估指标(Ritchie Ng)的回归问题:
- 平均绝对误差(MAE)是误差绝对值的平均值。
- 均方误差(MSE)是均方误差的均值。
- 均方根误差(RMSE)是均方根误差的均方根。
# calculate MAE using scikit-learn
print("MAE:", metrics.mean_absolute_error(y_test, y_pred))
#calculate mean squared error
print("MSE", metrics.mean_squared_error(y_test, y_pred))
# compute the RMSE of our predictions
print("RMSE:", np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
MAE: 595.0282284701234
MSE 2114139.8898678957
RMSE: 1454.0082151995896
RMSE比MSE和MAE更受欢迎, 因为由于相同的单位, RMSE可以用y解释。
CLTV的优缺点
CLTV可以帮助你设计有效的商业计划, 还可以提供扩展业务的机会。 CLTV可以吸引有意义的客户细分, 这些细分可以帮助你确定不同细分市场的需求。
客户终身价值是一种工具, 而不是一种战略。 CLTV可以找出最赚钱的客户, 但是你如何从他们那里获利, 这取决于你的策略。通常, CLTV模型会被混淆和滥用。对CLTV的痴迷可能会造成盲目性。公司只专注于寻找最佳的客户群, 并专注于他们并重复业务, 但是关注其他客户也很重要。
总结
恭喜, 你已完成本教程的结尾!
在本教程中, 你涵盖了有关客户生命周期价值的许多详细信息。你已经了解了客户生命周期的价值是什么, 计算CLTV的方法, 从头开始用python实现CLTV, CLTV的预测模型以及CLTV的利弊。此外, 你还介绍了熊猫的一些基本概念, 例如groupby和数据透视表, 用于汇总选定的数据列和数据行。
希望你现在可以利用CLTV概念来分析自己的数据集。感谢你阅读本教程!
如果你想了解有关使用Python分析客户数据的更多信息, 请参加srcmini的”客户分析和A / B测试Python”课程。
评论前必须登录!
注册