跳至内容
Python
数据科学

客户终身价值

在本教程中,学习如何在 Python 中计算客户终身价值。
Avinash Navlani's photo
Avinash Navlani
已更新 · 11分钟 阅读

使用 AI 探索

ChatGPTClaudePerplexity

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。

意大利经济学家维弗雷多·帕累托提出:80% 的结果来自 20% 的原因,这就是著名的 80/20 法则或帕累托法则。类似地,企业 80% 的业务往往来自 20% 的客户。企业需要识别这些顶级客户,并与他们保持关系以确保持续的收入。为了与客户维持长期关系,企业需要制定忠诚度计划,例如折扣、优惠、优惠券、积分和礼品。

获取新客户比留住现有客户更昂贵,因为您无需再次投入资源、时间和精力去获取新客户,您只需要让现有客户满意。业务分析师使用 CLTV(客户终身价值)准确计算获客成本。CLTV 表示在整个关系期间来自客户的总收入。CLTV 有助于企业将重心放在那些未来能带来更多收入的潜在客户上。

客户终身价值(CLTV)

“客户终身价值是一种货币数值,代表客户在整个关系期间将为公司带来的收入或利润总额”。CLTV 展示了获取长期客户相较于短期客户的影响。客户终身价值(CLV)可以帮助您回答每家公司在销售方面最重要的问题:

  • 如何识别最有利润的客户?
  • 公司如何提供最佳产品并获得最多利润?
  • 如何对盈利客户进行细分?
  • 需要投入多少预算来获取客户?

计算客户终身价值

计算 CLTV 有很多方法。每个人对此都有自己的看法。为了计算 CLTV,我们需要客户的历史数据,但对于新客户则无法直接计算。为了解决这个问题,业务分析师会开发机器学习模型来预测新客户的 CLTV。下面来看看一些 CLTV 的计算方法:

1)您可以在给定周期内累加来自客户的利润/收入。例如,如果某位客户过去 3 年一直与您保持合作,您可以将这 3 年内的所有利润相加。您可以按年、半年或月度计算平均利润,但使用这种方法无法为新客户构建预测模型。

2)为现有客户建立回归模型。取最近六个月的数据作为自变量,过去三年的总收入作为因变量,并据此建立回归模型。

3)也可以使用 RFM(Recency、Frequency、Monetary,即最近一次购买、购买频率和购买金额)进行 CLTV 实现。更多详情可参考我的教程。

4)使用以下等式:CLTV =((平均订单金额 × 购买频率)/ 流失率)× 利润率。

      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

加载数据集

首先使用 pandas 的 CSV 读取函数加载所需的 Online Retail 数据集。您可以从这里下载数据。

data = pd.read_excel("Online_Retail.xlsx")
data.head()
  InvoiceNo StockCode Description Quantity InvoiceDate UnitPrice CustomerID Country
0 536365 85123A WHITE HANGING HEART T-LIGHT HOLDER 6 2010-12-01 08:26:00 2.55 17850.0 United Kingdom
1 536365 71053 WHITE METAL LANTERN 6 2010-12-01 08:26:00 3.39 17850.0 United Kingdom
2 536365 84406B CREAM CUPID HEARTS COAT HANGER 8 2010-12-01 08:26:00 2.75 17850.0 United Kingdom
3 536365 84029G KNITTED UNION FLAG HOT WATER BOTTLE 6 2010-12-01 08:26:00 3.39 17850.0 United Kingdom
4 536365 84029E RED WOOLLY HOTTIE WHITE HEART. 6 2010-12-01 08:26:00 3.39 17850.0 United Kingdom

去重

有时您会拿到杂乱的数据集,需要处理重复记录,否则会影响分析结果。在 Python 中,pandas 提供了 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>
bar chart

在该数据集中,您可以看到大多数客户来自 “United Kingdom”。因此,您可以筛选出英国客户的数据。

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

pandas 的 describe() 函数可方便地获取各种汇总统计信息。它会返回数据的计数、均值、标准差、最小值、最大值以及分位数。

uk_data.describe()
  Quantity UnitPrice CustomerID
count 495478.000000 495478.000000 361878.000000
mean 8.605486 4.532422 15547.871368
std 227.588756 99.315438 1594.402590
min -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
max 80995.000000 38970.000000 18287.000000

这里可以看到,有些客户的下单数量为负数,这是不可能的。因此,您需要筛选数量大于 0 的记录。

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 帮助您统计发生交易的次数(频率)。
  • Quantity 是每笔交易中购买的商品数量。
  • UnitPrice 是客户购买的每个单位的价格,可用于计算总购买金额。
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()
  InvoiceDate InvoiceNo Quantity TotalPurchase
CustomerID        
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 spent_money
CustomerID        
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 spent_money avg_order_value
CustomerID          
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 spent_money avg_order_value profit_margin
CustomerID            
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 spent_money avg_order_value profit_margin CLV cust_lifetime_value
CustomerID                
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()
  CustomerID InvoiceDate InvoiceNo Quantity UnitPrice TotalPurchase month_yr
0 17850.0 2010-12-01 08:26:00 536365 6 2.55 15.30 Dec-2010
1 17850.0 2010-12-01 08:26:00 536365 6 3.39 20.34 Dec-2010
2 17850.0 2010-12-01 08:26:00 536365 8 2.75 22.00 Dec-2010
3 17850.0 2010-12-01 08:26:00 536365 6 3.39 20.34 Dec-2010
4 17850.0 2010-12-01 08:26:00 536365 6 3.39 20.34 Dec-2010

从 InvoiceDate 中提取月份和年份。

uk_data['month_yr'] = uk_data['InvoiceDate'].apply(lambda x: x.strftime('%b-%Y'))
uk_data.head()
  CustomerID InvoiceDate InvoiceNo Quantity UnitPrice TotalPurchase month_yr
0 17850.0 2010-12-01 08:26:00 536365 6 2.55 15.30 Dec-2010
1 17850.0 2010-12-01 08:26:00 536365 6 3.39 20.34 Dec-2010
2 17850.0 2010-12-01 08:26:00 536365 8 2.75 22.00 Dec-2010
3 17850.0 2010-12-01 08:26:00 536365 6 3.39 20.34 Dec-2010
4 17850.0 2010-12-01 08:26:00 536365 6 3.39 20.34 Dec-2010

数据透视表将列作为输入,并将条目分组为二维表,从而对数据进行多维度汇总。

sale=uk_data.pivot_table(index=['CustomerID'],columns=['month_yr'],values='TotalPurchase',aggfunc='sum',fill_value=0).reset_index()
sale.head()
month_yr CustomerID Apr-2011 Aug-2011 Dec-2010 Dec-2011 Feb-2011 Jan-2011 Jul-2011 Jun-2011 Mar-2011 May-2011 Nov-2011 Oct-2011 Sep-2011
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 CustomerID Apr-2011 Aug-2011 Dec-2010 Dec-2011 Feb-2011 Jan-2011 Jul-2011 Jun-2011 Mar-2011 May-2011 Nov-2011 Oct-2011 Sep-2011 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 个参数:特征、目标和测试集大小。另外,您可以使用 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-squared(决定系数)。R-squared 是模型解释方差的比例,取值介于 0 和 1 之间。值越高越好,因为这表示模型解释的方差越大。

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-squared 较高(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 的优缺点。同时,您还复习了 pandas 的一些基础概念,如 groupby 和数据透视表,用于对所选数据的列和行进行汇总。

希望您现在可以将 CLTV 的概念用于分析您自己的数据集。感谢阅读!

如果您想进一步学习如何在 Python 中分析客户数据,请参加 DataCamp 的 Customer Analytics & A/B Testing in Python 课程。

主题
Python
数据科学

Python 课程

课程

Python 入门

4 小时
7.1M
只需 4 小时就能掌握 Python 数据分析基础知识。 本在线课程将介绍 Python 接口并探索常用包。
查看详情开始课程

创建您的免费账户

实践并学习路径你的进步。

使用 Google 继续
继续操作即表示您接受我们的《使用条款》和《隐私政策》,并同意您的数据存储在美国。
查看更多