CDNow网站用户消费行为分析

本文通过对CDNow在线音乐零售商1997至1998年的用户交易数据进行深入分析,揭示了用户消费习惯、客户价值及生命周期特点。分析覆盖总体消费趋势、客户获取与留存策略、RFM客户价值分类及客户生命周期评估。

1.简介

1.1 数据集说明

CDNow曾经是一家在线音乐零售平台,后被德国波泰尔斯曼娱乐集团公司出资收购,其资产总价值在最辉煌时曾超过10亿美元。
本次分析数据来源CDNow网站的用户在1997年1月1日至1998年6月30日期间内购买CD交易明细。
数据集字段:用户ID,购买日期,订单数,订单金额。

1.2 分析思路

在这里插入图片描述

2.分析结果及建议

2.1 总体消费情况

(1)销量与销售额变化趋势
在这里插入图片描述
(2)用户消费能力
在这里插入图片描述
(3)用户消费时间
在这里插入图片描述

2.2 客户获取和留存

(1)每月新增用户
在这里插入图片描述
(2)月复购率与回购率
月复购率:在一个月内消费两次及以上的用户在总消费用户中占比。
月回购率:某个月内消费的用户,在下个月仍旧消费的占比。
在这里插入图片描述
在这里插入图片描述
(3)留存时间
将留存时间分段,分析不同留存时间与消费额、用户数的关系。
在这里插入图片描述
(4)消费周期
此处定义为距离上次购买的时间间隔。消费周期与商品属性有关,CD的消费周期显然比一般的必需品长。分析消费周期有利于召回客户、理解商品特性。
在这里插入图片描述

2.3 客户价值分析

(1)RFM客户价值分类
R(Recency)表示客户最近一次购买时间
F(Frequency)表示客户在时间内购买的次数
M (Monetary)表示客户在时间内购买的金额。
采用k-measn聚类算法对客户数据进行客户分群,分成5类。

在这里插入图片描述
(2)用户价值分析
在这里插入图片描述

2.4 客户生命周期分析

用户生命周期是指第一次消费至最后一次消费的时间。
(1)生命周期
在这里插入图片描述
(2)长生命周期客户分析
进一步分析生命周期在400天以上的客户。
在这里插入图片描述

3.数据处理过程

导入模块

import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
from datetime import datetime

%matplotlib inline
plt.style.use('ggplot')
plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

columns = ['user_id', 'order_dt', 'order_products', 'order_amount']#给表头命名
df = pd.read_table('CDNOW.txt', names = columns,sep = '\s+')#字符串是空格分割,用\s+表示匹配任意空白符
df.head()
user_idorder_dtorder_productsorder_amount
0119970101111.77
1219970112112.00
2219970112577.00
3319970102220.76
4319970330220.76
3.1 数据预处理
#查看基本信息
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   user_id         69659 non-null  int64  
 1   order_dt        69659 non-null  int64  
 2   order_products  69659 non-null  int64  
 3   order_amount    69659 non-null  float64
dtypes: float64(1), int64(3)
memory usage: 2.1 MB

没有数据缺失

#查看是否有重复数据
sum(df.duplicated())
255
#去除重复数据
df.drop_duplicates(inplace = True)
sum(df.duplicated())
0
#有无异常数据
df.describe()
user_idorder_dtorder_productsorder_amount
count69404.0000006.940400e+0469404.00000069404.000000
mean11468.9137661.997228e+072.41455835.963097
std6814.3686053.837687e+032.33652836.318489
min1.0000001.997010e+071.0000000.000000
25%5509.0000001.997022e+071.00000014.490000
50%11410.0000001.997042e+072.00000025.980000
75%17261.0000001.997111e+073.00000043.720000
max23570.0000001.998063e+0799.0000001286.010000

订单金额有0值,可能是赠品或减免商品,这部分客户没有太大价值,应该删除后再分析。

df.query('order_amount == 0').info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 80 entries, 1548 to 68593
Data columns (total 4 columns):
 #   Column          Non-Null Count  Dtype  
---  ------          --------------  -----  
 0   user_id         80 non-null     int64  
 1   order_dt        80 non-null     int64  
 2   order_products  80 non-null     int64  
 3   order_amount    80 non-null     float64
dtypes: float64(1), int64(3)
memory usage: 3.1 KB

订单金额为0值的数有80条

#删除订单金额为0的数据
df = df.drop(df[df.order_amount == 0].index)
df.describe()
user_idorder_dtorder_productsorder_amount
count69324.0000006.932400e+0469324.00000069324.000000
mean11470.2275691.997228e+072.41619136.004598
std6813.9095523.838451e+032.33738236.318874
min1.0000001.997010e+071.0000001.630000
25%5509.7500001.997022e+071.00000014.490000
50%11414.0000001.997042e+072.00000025.980000
75%17262.2500001.997111e+073.00000043.730000
max23570.0000001.998063e+0799.0000001286.010000
#转换时间格式,提取月份和天数
df['order_dt'] = pd.to_datetime(df['order_dt'],format = '%Y%m%d')
df['date'] = df.order_dt.dt.date
df['month'] = df.order_dt.values.astype('datetime64[M]')

df.head()
user_idorder_dtorder_productsorder_amountdatemonth
011997-01-01111.771997-01-011997-01-01
121997-01-12112.001997-01-121997-01-01
221997-01-12577.001997-01-121997-01-01
331997-01-02220.761997-01-021997-01-01
431997-03-30220.761997-03-301997-03-01
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 69324 entries, 0 to 69658
Data columns (total 6 columns):
 #   Column          Non-Null Count  Dtype         
---  ------          --------------  -----         
 0   user_id         69324 non-null  int64         
 1   order_dt        69324 non-null  datetime64[ns]
 2   order_products  69324 non-null  int64         
 3   order_amount    69324 non-null  float64       
 4   date            69324 non-null  object        
 5   month           69324 non-null  datetime64[ns]
dtypes: datetime64[ns](2), float64(1), int64(2), object(1)
memory usage: 3.7+ MB
#订单的时间范围
min(df.order_dt),max(df.order_dt)
(Timestamp('1997-01-01 00:00:00'), Timestamp('1998-06-30 00:00:00'))

该数据的订单时间是从1997-01-01到1998-06-30。

3.2 数据分析及可视化

1.总体消费情况

每个用户的消费数据

data_by_user = df.groupby('user_id').sum()
data_by_user.head()
order_productsorder_amount
user_id
1111.77
2689.00
316156.46
47100.50
529385.61
data_by_user.describe()
order_productsorder_amount
count23502.00000023502.000000
mean7.127053106.202993
std16.950784240.494298
min1.0000003.990000
25%1.00000019.990000
50%3.00000043.530000
75%7.000000106.775000
max1033.00000013925.980000

从单个用户来看,平均每个用户购买7件商品,最多购买1033件。用户的平均消费金额是106,最低消费3.33,最高消费13925。

每个月的消费数据

#每个月的销量
plt.figure(figsize = (16,6))

plt.subplot(1,2,1)
df.groupby(['month']).order_products.sum().plot(style = '--.',alpha = 0.8,grid = True)
plt.title('每个月的销量')


#每个月的销售额
plt.subplot(1,2,2)
df.groupby(['month']).order_amount.sum().plot(style = '--.',alpha = 0.8,grid = True)
plt.title('每个月的销售额')

在这里插入图片描述

销量与销售额呈现相同的变化趋势。前几个月的销量和销售额都很高,97年3月后迅速下降,97年5月后趋于稳定。
为什么数据变化这么大?可能是早期用户数据异常偏高,或者是前期有促销活动、经营策略上的差异。

进一步分析早期用户数据是否异常:

#绘制97年5月前每笔订单的销量-销售额散点图
fig, axes = plt.subplots(1,2, figsize=(16,6))
df[df.month < pd.Timestamp('1997-05-01 00')].plot.scatter(x = 'order_amount', y = 'order_products',ax = axes[0],title = '97年5月前每笔订单的散点图')


#绘制97年5月前每个用户的销量-销售额散点图
df[df.month < pd.Timestamp('1997-05-01 00')].groupby('user_id').sum().plot.scatter(x = 'order_amount', y = 'order_products',ax = axes[1])
plt.title('97年5月前每个用户的散点图')

在这里插入图片描述

销售额与订单商品数基本呈正相关。有少部分订单销售额和商品数较大,用户数据的极值更少。因此前期数据并无异常。

用户消费能力

#用户购买量
plt.figure(figsize = (16,6))
plt.subplot(1,2,1)
df.groupby('user_id').order_products.sum().hist(bins = range(0,150,5))
plt.title('用户购买量分布直方图')
plt.xlabel('购买量')
plt.ylabel('人数')
#用户消费金额
plt.subplot(1,2,2)
df.groupby('user_id').order_amount.sum().hist(bins = range(0,1500,50))
plt.title('用户消费金额分布直方图')
plt.xlabel('消费金额')
plt.ylabel('人数')

在这里插入图片描述

大部分用户的消费能力较低,购买量在10件以内,消费金额在100以内。用户消费能力遵从二八法则,大约20%的用户产生80%的收益。

用户消费时间

#用户第一次消费时间
pay_first = df.groupby('user_id').month.min().value_counts()
pay_first
1997-02-01    8455
1997-01-01    7814
1997-03-01    7231
1997-11-01       2
Name: month, dtype: int64
#用户最后用一次消费时间
pay_last = df.groupby('user_id').month.max().value_counts().sort_index()
pay_last
1997-01-01    4162
1997-02-01    4892
1997-03-01    4460
1997-04-01     677
1997-05-01     480
1997-06-01     499
1997-07-01     493
1997-08-01     384
1997-09-01     397
1997-10-01     455
1997-11-01     609
1997-12-01     620
1998-01-01     514
1998-02-01     551
1998-03-01     992
1998-04-01     769
1998-05-01    1042
1998-06-01    1506
Name: month, dtype: int64

可以看出,用户的第一次消费全都集中在前三个月,大部分用户的最后一次消费也集中在前三个月,后几个月缓慢减少。这就是前三个月销售数据高的原因。
此数据集只是部分用户在这18个月里的销售数据,不是这18个月里的所有用户,因此分析存在一定局限性。

2.客户获取和留存分析

每月新增用户数

pay_first.sort_index().plot(kind = 'bar')

在这里插入图片描述
97年1月、2月、3月、11月有新增用户,其他月份没有新增用户。

月复购率与回购率
月复购率:在一个月内消费两次及以上的用户在总消费用户中占比。
月回购率:某个月内消费的用户,在下个月仍旧消费的占比。

#计算每个用户在每月的购买次数
count_by_month = pd.pivot_table(df, values = 'order_dt', index = 'user_id', columns = 'month', aggfunc = 'count').fillna(0)
count_by_month.head()
month1997-01-011997-02-011997-03-011997-04-011997-05-011997-06-011997-07-011997-08-011997-09-011997-10-011997-11-011997-12-011998-01-011998-02-011998-03-011998-04-011998-05-011998-06-01
user_id
11.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.0
22.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.00.0
31.00.01.01.00.00.00.00.00.00.02.00.00.00.00.00.01.00.0
42.00.00.00.00.00.00.01.00.00.00.01.00.00.00.00.00.00.0
52.01.00.01.01.01.01.00.01.00.00.02.01.00.00.00.00.00.0
#将数据转换一下,消费两次及以上记为1,消费一次记为0,没有消费记为NaN
count_by_month1 = count_by_month.applymap(lambda x: 1 if x >1 else np.NaN if x == 0 else 0)
count_by_month1.head()
month1997-01-011997-02-011997-03-011997-04-011997-05-011997-06-011997-07-011997-08-011997-09-011997-10-011997-11-011997-12-011998-01-011998-02-011998-03-011998-04-011998-05-011998-06-01
user_id
10.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
21.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
30.0NaN0.00.0NaNNaNNaNNaNNaNNaN1.0NaNNaNNaNNaNNaN0.0NaN
41.0NaNNaNNaNNaNNaNNaN0.0NaNNaNNaN0.0NaNNaNNaNNaNNaNNaN
51.00.0NaN0.00.00.00.0NaN0.0NaNNaN1.00.0NaNNaNNaNNaNNaN
#计算复购率
repay_rate_by_month = count_by_month1.sum()/count_by_month1.count()
repay_rate_by_month.plot(style = '--.',alpha = 0.8,grid = True,figsize = (18,6))
plt.title('月复购率')

在这里插入图片描述

前三个月大量新客增加,因此复购率不高,在5%-15%之间,3月后的用户都是老客,复购较稳定,在20%左右。

月回购率

#购买过的用户记为1,没购买过的记为0
pay_user = count_by_month.applymap(lambda x: 1 if x > 0 else 0)
pay_user.head()
month1997-01-011997-02-011997-03-011997-04-011997-05-011997-06-011997-07-011997-08-011997-09-011997-10-011997-11-011997-12-011998-01-011998-02-011998-03-011998-04-011998-05-011998-06-01
user_id
1100000000000000000
2100000000000000000
3101100000010000010
4100000010001000000
5110111101001100000
#回购用户函数:

def pay_return(data):
    pay_by_month = []
    
    for i in range(17):#循环前17列
        if data[i] == 1:
            if data[i+1] == 1:
                pay_by_month.append(1)#如果本月购买过,且在下月也购买过,记为1
            if data[i+1] ==  0:
                pay_by_month.append(0)#如果本月购买过,且在下月没买,记为0
        else:
            pay_by_month.append(np.NaN)#其他情况记为NaN
    pay_by_month.append(np.NaN)#最后一列填充NaN值
    return pd.Series(pay_by_month,index = pay_user.columns)#将列表pay_by_month转换为series
    
pay_return_by_month =  pay_user.apply(pay_return, axis = 1)#对数据集的每一行使用函数
pay_return_by_month.head()

month1997-01-011997-02-011997-03-011997-04-011997-05-011997-06-011997-07-011997-08-011997-09-011997-10-011997-11-011997-12-011998-01-011998-02-011998-03-011998-04-011998-05-011998-06-01
user_id
10.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
20.0NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN
30.0NaN1.00.0NaNNaNNaNNaNNaNNaN0.0NaNNaNNaNNaNNaN0.0NaN
40.0NaNNaNNaNNaNNaNNaN0.0NaNNaNNaN0.0NaNNaNNaNNaNNaNNaN
51.00.0NaN1.01.01.00.0NaN0.0NaNNaN1.00.0NaNNaNNaNNaNNaN
#计算回购率
pay_return_rate = pay_return_by_month.sum()/pay_return_by_month.count()

pay_return_rate.plot(style = '--.',alpha = 0.8,grid = True,figsize = (18,6))
plt.title('月回购率')

在这里插入图片描述

回购率与复购率的变化趋势一致。前三个月的回购率较低,3月后回购率稳定在30%左右。新客的回购率在15%-20%,老客的回购是30%。
根据复购率和回购率可知,老客的复购和回购远高于新客,忠诚度更高,

留存时间分析
将留存时间分段,分析不同留存时间与消费额、用户数的关系。

df.groupby('user_id').order_dt.min().reset_index()
user_idorder_dt
011997-01-01
121997-01-12
231997-01-02
341997-01-01
451997-01-01
.........
23497235661997-03-25
23498235671997-03-25
23499235681997-03-25
23500235691997-03-25
23501235701997-03-25

23502 rows × 2 columns

#计算个用户的最早消费时间
user_retention = pd.merge(df,df.groupby('user_id').order_dt.min().reset_index(),on = 'user_id',suffixes = ('','_min'))
#计算每笔订单的留存天数
user_retention['留存天数'] = (user_retention.order_dt - user_retention.order_dt_min).astype('timedelta64[D]')
user_retention.head()
user_idorder_dtorder_productsorder_amountdatemonthorder_dt_min留存天数
011997-01-01111.771997-01-011997-01-011997-01-010.0
121997-01-12112.001997-01-121997-01-011997-01-120.0
221997-01-12577.001997-01-121997-01-011997-01-120.0
331997-01-02220.761997-01-021997-01-011997-01-020.0
431997-03-30220.761997-03-301997-03-011997-01-0287.0
user_retention['留存天数'].max()
544.0
#给留存天数分段:
bin = [0,3,7,15,30,60,90,120,150,180,210,240,270,300,330,365,544]
user_retention['留存天数分段'] = pd.cut(user_retention['留存天数'],bins = bin)

#用户在第一次消费之后,在后续各时间段内的消费总额
pivoted_retention = user_retention.pivot_table(index = 'user_id',columns ='留存天数分段',values = 'order_amount',aggfunc = sum)
pivoted_retention.head()
留存天数分段(0, 3](3, 7](7, 15](15, 30](30, 60](60, 90](90, 120](120, 150](150, 180](180, 210](210, 240](240, 270](270, 300](300, 330](330, 365](365, 544]
user_id
3NaNNaNNaNNaNNaN40.3NaNNaNNaNNaNNaNNaNNaN78.41NaN16.99
4NaNNaNNaN29.73NaNNaNNaNNaNNaNNaN14.96NaNNaNNaN26.48NaN
5NaNNaN13.97NaN38.90NaN45.5538.7126.1428.14NaN40.47NaNNaN86.9337.47
7NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN97.43NaNNaN138.50
8NaNNaNNaNNaN13.97NaNNaNNaN45.2936.76NaNNaNNaN53.4213.9924.46
#各留存时间段的平均消费额
plt.figure(figsize = (12,6))
pivoted_retention.mean().plot.bar()
plt.title('各留存时间段的平均消费额')

在这里插入图片描述

#各留存时间段的用户数
pivoted_retention_counts = pivoted_retention.fillna(0).applymap(lambda x:1 if x > 0 else 0)
pivoted_retention_counts.head()
留存天数分段(0, 3](3, 7](7, 15](15, 30](30, 60](60, 90](90, 120](120, 150](150, 180](180, 210](210, 240](240, 270](270, 300](300, 330](330, 365](365, 544]
user_id
30000010000000101
40001000000100010
50010101111010011
70000000000001001
80000100011000111
plt.figure(figsize = (12,6))
(pivoted_retention_counts.sum()/pivoted_retention_counts.count()).plot.bar()
plt.title('各留存时间段的用户占比')

在这里插入图片描述

第一次消费后0-3天内、3-7天内,用户可能消费更多,但这两类用户占比只有5%和7%,显然不高。
其他留存时段的消费金额差距不大,都在50左右,所以重点比较各个时段的用户数。
第一次消费后15-30天内、30-60天内、60-90天内的客户,数量最多,占比达到18%、26%、21%,消费额接近总体平均值。因此,第一次消费后15-30天内、30-60天内、60-90天内,用户再次消费的可能性很高,是提高留存率的好时机。

用户消费周期
此处定义为距离上次购买的时间间隔。消费周期与商品属性有关,CD的消费周期显然比一般的必需品长。分析消费周期有利于召回客户、理解商品特性。

#计算每个用户每次消费距上次消费的时间间隔
def diff(data):
    diffs = (data.order_dt - data.order_dt.shift(-1)).astype('timedelta64[D]')
    return diffs

last_diffs = user_retention.groupby('user_id').apply(diff)
last_diffs
user_id       
1        0         NaN
2        1         0.0
         2         NaN
3        3       -87.0
         4        -3.0
                  ... 
23568    69319   -17.0
         69320     NaN
23569    69321     NaN
23570    69322    -1.0
         69323     NaN
Name: order_dt, Length: 69324, dtype: float64
plt.figure(figsize = (12,6))
last_diffs.hist(bins = 50)
plt.title('用户消费周期分布图')

在这里插入图片描述

#平均消费周期
last_diffs.mean()
-69.36085286543582

用户的平均消费周期是69天,因此,想要召回客户,最佳时期是用户购买后的60-70天左右。
大部分用户消费间隔较短,集中在10-20天以内,可以在不同的消费周期内使用不同的营销策略,比如消费后邀请加入会员,消费10天后发放优惠券,20天后邀请填写评价、优惠券到期提醒,60天后APP或短信推送消息。

3.客户价值分析

RFM用户价值分类:
R(Recency)表示客户最近一次购买时间
F(Frequency)表示客户在时间内购买的次数
M (Monetary)表示客户在时间内购买的金额。

#计算每笔订单的r
df['order_interval']= pd.to_datetime('1998-06-30')- df['order_dt']#距今购买时间
df['order_interval'] = df.order_interval.astype('timedelta64[D]')#提取天数
df.head()
user_idorder_dtorder_productsorder_amountdatemonthorder_interval
011997-01-01111.771997-01-011997-01-01545.0
121997-01-12112.001997-01-121997-01-01534.0
221997-01-12577.001997-01-121997-01-01534.0
331997-01-02220.761997-01-021997-01-01544.0
431997-03-30220.761997-03-301997-03-01457.0
#计算RFM
rfm = df.groupby('user_id',as_index = False).agg({'order_interval': 'min', 'order_products': 'count', 'order_amount':'sum'})
rfm.columns = ['user_id','r', 'f', 'm']
rfm.head()
user_idrfm
01545.0111.77
12534.0289.00
2333.06156.46
34200.04100.50
45178.011385.61
rfm.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 23502 entries, 0 to 23501
Data columns (total 4 columns):
 #   Column   Non-Null Count  Dtype  
---  ------   --------------  -----  
 0   user_id  23502 non-null  int64  
 1   r        23502 non-null  float64
 2   f        23502 non-null  int64  
 3   m        23502 non-null  float64
dtypes: float64(2), int64(2)
memory usage: 918.0 KB

标准化处理数据

#标准化
from sklearn.preprocessing import StandardScaler#通过(X-X_mean)/std计算,使所有数据聚集在0附近


#使用 StandardScaler 来缩放数据集中的所有变量,将结果存储在 rfm_scaled 中。 
rfm_scaled = StandardScaler()

#创建一个 pandas 数据帧并存储缩放的 x 变量以及 y_train。命名为 training_data 。
rfm_standar = rfm_scaled.fit_transform(rfm.iloc[:,1:])
rfm_standar = pd.DataFrame(rfm_standar,columns = ['r','f','m'])
rfm_standar['user_id'] = rfm['user_id']
rfm_standar.head()
rfmuser_id
00.982776-0.416202-0.3926701
10.922105-0.202733-0.0715332
2-1.8411920.6511440.2089783
3-0.9200930.224205-0.0237144
4-1.0414361.7184891.1618285
rfm_standar.describe()
rfmuser_id
count2.350200e+042.350200e+042.350200e+0423502.000000
mean9.646781e-172.234993e-155.175729e-1611789.461535
std1.000021e+001.000021e+001.000021e+006802.223681
min-2.023206e+00-4.162021e-01-4.250212e-011.000000
25%-8.856209e-01-4.162021e-01-3.584901e-015901.250000
50%5.746244e-01-4.162021e-01-2.606063e-0111790.500000
75%7.621536e-011.073613e-022.378513e-0317678.750000
max9.827761e-014.569313e+015.746528e+0123570.000000

采用k-measn聚类算法对客户数据进行客户分群,分成5类

from sklearn.cluster import KMeans #导入K均值聚类算法
#调用k-means算法,进行聚类分析
kmodel = KMeans(n_clusters = 5, n_jobs = 4) #n_jobs是并行数,一般等于CPU数较好
kmodel.fit(rfm_standar.iloc[:,[0,1,2]]) #训练模型

r1 = pd.DataFrame(kmodel.cluster_centers_) #各个类别的聚类中心
r2 = pd.Series(kmodel.labels_).value_counts() #统计各个类别的数目

rfm_model = pd.concat([r1,r2], axis = 1)#合并
rfm_model.columns = ['r','f','m','标签数']
rfm_model.head()
rfm标签数
0-1.2677060.2978150.1456176469
10.650241-0.337605-0.26389215789
2-1.6518592.2972802.0473651168
3-1.7450108.1547309.64800773
4-2.01217539.57368240.9495643
rfm_model['各标签占比'] = rfm_model['标签数']/rfm_model['标签数'].sum()
rfm_model.head()
rfm标签数各标签占比
0-1.2677060.2978150.14561764690.275253
10.650241-0.337605-0.263892157890.671815
2-1.6518592.2972802.04736511680.049698
3-1.7450108.1547309.648007730.003106
4-2.01217539.57368240.94956430.000128
#将标签加入原数据中
rfm_standar['label'] = pd.Series(kmodel.labels_)
df = pd.merge(df, rfm_standar.iloc[:,[3,4]],on = 'user_id')
df.head()
user_idorder_dtorder_productsorder_amountdatemonthorder_intervallabel
011997-01-01111.771997-01-011997-01-01545.01
121997-01-12112.001997-01-121997-01-01534.01
221997-01-12577.001997-01-121997-01-01534.01
331997-01-02220.761997-01-021997-01-01544.00
431997-03-30220.761997-03-301997-03-01457.00
df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 69324 entries, 0 to 69323
Data columns (total 8 columns):
 #   Column          Non-Null Count  Dtype         
---  ------          --------------  -----         
 0   user_id         69324 non-null  int64         
 1   order_dt        69324 non-null  datetime64[ns]
 2   order_products  69324 non-null  int64         
 3   order_amount    69324 non-null  float64       
 4   date            69324 non-null  object        
 5   month           69324 non-null  datetime64[ns]
 6   order_interval  69324 non-null  float64       
 7   label           69324 non-null  int32         
dtypes: datetime64[ns](2), float64(2), int32(1), int64(2), object(1)
memory usage: 4.5+ MB

画出密度函数

def density_plot(data): #自定义作图函数  
    p = data.iloc[:,[0,1,2]].plot(kind='kde', title = '标签为{}的rfm概率密度'.format(i),figsize = (12,5),linewidth = 2, subplots = True, sharex = False)   
    rfm_mean = [9.6, 2.2, 5.2]
    [p[i].set_ylabel('density') for i in range(3)]
    [p[i].axvline(x = rfm_mean[i]) for i in range(3)]
    plt.legend()
    return plt


for i in range(5):
    density_plot(rfm_standar[rfm_standar['label']==i])

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

根据rfm概率密度可知,不同标签的用户有不同的特征:
标签为0的客户,R、F、M最小;标签为1的客户,在R属性上最大,在F、M属性上最小;标签为2的客户在R很小、F、M较小;标签为3的客户,R很小,F、M较大;标签为4的客户,R很小,F、M最大。

#用户分类
rfm_model['用户分类'] = ['有潜力的一般客户','一般与低价值客户','重要发展客户','重要保持客户','高价值客户']
rfm_model.head()
rfm标签数各标签占比用户分类
0-1.2677060.2978150.14561764690.275253有潜力的一般客户
10.650241-0.337605-0.263892157890.671815一般与低价值客户
2-1.6518592.2972802.04736511680.049698重要发展客户
3-1.7450108.1547309.648007730.003106重要保持客户
4-2.01217539.57368240.94956430.000128高价值客户

根据RFM特征描述,将客户分为五类:
1、高价值客户:最近消费时间近、消费频次和消费金额都极高,这类客户只有3个。
2、重要保持客户:消费时间近、消费频次和消费金额都较高,这类客户占比0.3%,应尽可能延长这类客户的高消费水平。
3、重要发展客户:消费时间近、消费频次接近平均值,消费金额略低于平均值,这类客户占比5%,应该重点提高他们的消费金额。
4、有潜力的一般客户:消费时间较近、消费频次和消费金额都较低,这类客户占比27%,应该重点提高消费频次,进而再提高消费金额。
5、一般与低价值客户:最近消费时间较远、消费频次和消费金额都很低,占比67%,虽然这类用户的价值较低,但基数庞大,应该重点关注和提高留存率,发掘潜在用户。

总体来看,高价值客户、重要保持客户、重要发展客户、有潜力的一般客户都属于价值较高的客户,是重点关注对象,占比30%左右,针对不同客户群体,应该运用不同的营销策略。

用户价值分析:

#每个用户的累计消费金额并排序
user_amount = df.groupby('user_id').order_amount.sum().sort_values().reset_index()
#计算用户消费金额累加值、比例
user_amount['用户累计消费金额'] = user_amount.order_amount.cumsum()
user_amount['用户累计消费比例'] = user_amount['用户累计消费金额']/user_amount['用户累计消费金额'].max()
user_amount.tail()
user_idorder_amount用户累计消费金额用户累计消费比例
2349779316497.182459567.660.985411
23498193396552.702466120.360.988036
2349979836960.082473080.440.990824
23500140488976.332482056.770.994421
23501759213925.982495982.751.000000
plt.figure(figsize = (12,6))
user_amount['用户累计消费比例'].plot()
plt.title('用户消费额累计贡献')
plt.xlabel('人数')
plt.ylabel('用户消费额累计贡献')

在这里插入图片描述

前20000个用户贡献了40%的消费。后面4000位用户贡献了60%,呈现28倾向。

#每个用户的累计销量并排序
user_counts = df.groupby('user_id').order_dt.count().sort_values().reset_index()
#计算用户销量累加值、比例
user_counts['用户累计销量'] = user_counts.order_dt.cumsum()
user_counts['用户累计销量比例'] = user_counts['用户累计销量']/user_counts['用户累计销量'].max()
user_counts.tail()
user_idorder_dt用户累计销量用户累计销量比例
234973049110686170.989802
2349822061142687590.991850
234997983148689070.993985
235007592200691070.996870
2350114048217693241.000000
plt.figure(figsize = (12,6))
user_counts['用户累计销量比例'].plot()
plt.title('用户销量累计贡献')
plt.xlabel('人数')
plt.ylabel('用户销量累计贡献')

在这里插入图片描述

前2000个用户贡献了45%的销量,后面4000个用户贡献了55%的销量。

4.客户生命周期分析
用户生命周期是指第一次消费至最后一次消费的时间。

#用户第一次消费的时间
oder_date_min = df.groupby('user_id').order_dt.min()
#用户最后一次消费的时间
oder_date_max = df.groupby('user_id').order_dt.max()
clc = (oder_date_max - oder_date_min).astype('timedelta64[D]')
#用户平均生命周期、最长生命周期
clc.mean(), clc.max()
(135.23329929367713, 544.0)

客户的平均生命周期是135天,最长生命周期是544天。

plt.figure(figsize = (12,6))
clc.hist(bins = 50)
plt.title('客户生命周期分布图')
plt.xlabel('生命周期')
plt.ylabel('人数')

在这里插入图片描述

大部分用户的生命周期集中在前10天内,即大部分用户只消费了一次。

去除只消费一次的客户:

plt.figure(figsize = (12,6))
clc[clc != 0].hist(bins = 100)
plt.title('客户生命周期分布图')
plt.xlabel('生命周期')
plt.ylabel('人数')

在这里插入图片描述

仍有部分用户的生命周期集中在30天内,虽然已经二次消费,但仍然有客户流失。同时有一大部分用户生命周期大于400天,属于忠诚客户。

#消费两次以上的用户生命平均周期
clc[clc != 0].mean()
276.05776079214803

消费两次及以上的客户,其平均生命周期是276天,相较于总体平均值135天,提高了两倍。因此,用户首次消费后应该引导其进行再次消费,提高用户复购率,可以延长客户2倍的生命周期。

分析忠诚客户:
进一步分析生命周期在400天以上的客户

clc_400 = pd.DataFrame([clc[clc >= 400]]).T.reset_index()
clc_400 = clc_400.rename(columns = {'order_dt':'clc'})
clc_400.head()
user_idclc
03511.0
17445.0
28452.0
39523.0
411415.0
user_clc_400_ = pd.merge(df,clc_400.reset_index(),on = 'user_id')
user_clc_400_.head()
user_idorder_dtorder_productsorder_amountdatemonthorder_intervallabelindexclc
031997-01-02220.761997-01-021997-01-01544.000511.0
131997-03-30220.761997-03-301997-03-01457.000511.0
231997-04-02219.541997-04-021997-04-01454.000511.0
331997-11-15557.451997-11-151997-11-01227.000511.0
431997-11-25420.961997-11-251997-11-01217.000511.0
plt.figure(figsize = (8,6))
user_clc_400_.groupby('user_id').order_amount.sum().hist(bins = 200)
plt.title('生命周期在400天以上的客户消费额分布')
plt.xlabel('消费额')
plt.ylabel('人数')

在这里插入图片描述

#用户占比、用户消费金额占比、用户销量占比
pd.DataFrame([clc_400.user_id.count()/df.user_id.nunique(),user_clc_400_.order_amount.sum()/df.order_amount.sum(),user_clc_400_.order_dt.count()/df.order_dt.count()],index = ['用户占比','用户消费金额占比','用户销量占比'])
0
用户占比0.157178
用户消费金额占比0.453051
用户销量占比0.427327

生命周期在400天及以上的用户,大部分人的消费金额在500以内,用户数量占15.7%,消费额占45%,销量占42.7%,贡献了将近一半的营收和销量,是忠诚且价值较高的客户,应该重点关注。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值