某健身平台会员用户消费行为分析

数据集简介

数据集来源于某健身房2019年3月至2020年2月会员消费购买行为,数据集一共包含四个字段:用户ID,购买日期,购买数量和购买金额。属于非常典型的消费行为数据集。

数据导入

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt#导入库及所需的包
from datetime import datetime
plt.rc('font', family='SimHei', size=18)# 显示中文标签
plt.style.use ('ggplot')#设定绘图风格
df=pd.read_excel(r"D:\PycharmProjects\data\cuscapi.xls", order_dt=['date'])# 数据加载
df.head(10)
user_id order_dt order_products order_amount
0 vs30033073 2020-01-17 1 20
1 vs30026748 2019-12-04 1 20
2 vs10000716 2019-07-05 1 20
3 vs30032785 2019-08-21 2 0
4 vs10000716 2019-10-24 1 20
5 vs30033073 2019-11-29 2 20
6 vs10000621 2019-07-19 2 20
7 vs30029475 2019-05-17 1 20
8 vs30030664 2019-11-11 1 20
9 vs10000773 2019-11-25 1 20
pd.set_option('display.float_format', lambda x: '%.2f' % x)
df.describe()
order_products order_amount
count 2013.00 2013.00
mean 1.47 22.90
std 0.91 94.94
min 1.00 0.00
25% 1.00 20.00
50% 1.00 20.00
75% 2.00 20.00
max 12.00 2650.00

分析:
1.会员用户平均每笔订单购买1.5个商品,标准差为在0.9,波性较小 。中位数在1个商品,75分位数在2个产品,说明绝大订单的购买量都不多。
2.平均每笔订单消费金额为22.9元,标准差约为95,中位数在20,平均数大于中位数。大多数会员消费金额集中在小额,小部分用户贡献大额消费,符合消费类数据的二八分布。
3.一般而言,消费类数据的分布都是长尾分布。

user_group=df.groupby('user_id').sum()
user_group.head(10)
user_id order_products order_amount
vs10000005 9 189
vs10000621 214 5704
vs10000627 2 0
vs10000716 250 2616
vs10000743 1 20
vs10000757 75 1104
vs10000773 23 460
vs10000775 8 2730
vs10000788 7 144
vs10000794 1 0
user_group.describe()
order_products order_amount
count 247.00 247.00
mean 11.97 186.59
std 36.70 641.12
min 1.00 0.00
25% 2.00 0.00
50% 2.00 0.00
75% 3.00 66.00
max 277.00 5704.00

分析:会员用户平均购买约12个商品,最多的购买了277个商品。会员用户平均消费金额约为187元,标准差为641,中位数在0,结合分位数和最大值看,属于正偏分布,存在小部分会员购买大量商品的高消费情况。

df.info()#查看数据类型
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 2013 entries, 0 to 2012
Data columns (total 4 columns):
user_id           2013 non-null object
order_dt          2013 non-null datetime64[ns]
order_products    2013 non-null int64
order_amount      2013 non-null int64
dtypes: datetime64[ns](1), int64(2), object(1)
memory usage: 63.0+ KB

分析:经查,本数据集不存在空值。

数据处理

数据类型转换

#提取月份
df['order_dt']=df['order_dt'].dt.date
df['month']=df['order_dt'].astype('datetime64[M]')
df.head(10)
user_id order_dt order_products order_amount month
0 vs30033073 2020-01-17 1 20 2020-01-01
1 vs30026748 2019-12-04 1 20 2019-12-01
2 vs10000716 2019-07-05 1 20 2019-07-01
3 vs30032785 2019-08-21 2 0 2019-08-01
4 vs10000716 2019-10-24 1 20 2019-10-01
5 vs30033073 2019-11-29 2 20 2019-11-01
6 vs10000621 2019-07-19 2 20 2019-07-01
7 vs30029475 2019-05-17 1 20 2019-05-01
8 vs30030664 2019-11-11 1 20 2019-11-01
9 vs10000773 2019-11-25 1 20 2019-11-01

数据分析-月度总趋势分析

df.groupby('month').order_amount.sum().plot()
plt.xlabel('月份')
plt.ylabel('消费金额(元)')
plt.title('不同月份的用户消费金额',fontsize=20)
output_17_1.png

分析:按月统计每个月的商品消费金额,可以看到,各月份销量波动起伏较大。

df.groupby('month').order_products.sum().plot()
plt.xlabel('月份')
plt.ylabel('商品个数')
plt.title('不同月份的产品购买量',fontsize=20)
output_19_1.png

说明:每月的产品购买量呈现前7个月快速上升,后5个月整体下降的趋势。

df.groupby('month').user_id.count().plot()
plt.xlabel('月份')
plt.ylabel('消费次数')
plt.title('不同月份的消费次数',fontsize=20)
output_21_1.png

说明:至7月份消费次数超过250次,后续月份的消费次数开始呈现下降趋势。

df.groupby('month').user_id.nunique().plot()
plt.xlabel('月份')
plt.ylabel('消费人数')
plt.title('不同月份的消费人数',fontsize=20)
output_23_1.png

说明:每月的消费人数小于每月的消费次数。至7月份消费人数达90人,后续月份的消费人数开始呈现下降趋势。

数据分析-用户个体行为分析

df.groupby('user_id').sum().head()
user_id order_products order_amount
vs10000005 9 189
vs10000621 214 5704
vs10000627 2 0
vs10000716 250 2616
vs10000743 1 20
user_consume=df.groupby('user_id').sum()
plt.scatter(user_consume['order_products'], user_consume['order_amount'] ) 
plt.xlabel('消费产品个数')
plt.ylabel('消费金额')
plt.title('用户消费金额与产品个数的关系散点图',fontsize=20)
output_27_1.png

说明:订单消费金额和订单商品量的关系不呈线性,用户消费规律性不强,订单的极值较多。

consume_products = user_consume['order_products']
consume_amount= user_consume['order_amount'] 

fig= plt.figure(figsize=(10.,6))
fig.add_subplot(1,2,1)
consume_products.hist(bins=10 )
plt.title('用户购买数量分布直方图')
plt.xlabel('购买数量')
plt.ylabel('人数')

fig.add_subplot(1,2,2)
consume_amount.hist(bins=10) 
plt.title('用户购买金额分布直方图')
plt.xlabel('购买金额')
plt.ylabel('人数')
output_29_1.png

说明:大部分用户消费能力不高,整个计算周期内购买数量在50以内,消费金额在1000以内。

df.groupby('user_id').month.min().value_counts()
2019-08-01   62
2019-07-01    53
2019-09-01    43
2019-10-01    22
2019-11-01    16
2019-03-01    13
2020-01-01    11
2019-06-01     9
2019-05-01     8
2019-12-01     5
2020-02-01     3
2019-04-01     2
Name: month, dtype: int64
df.groupby('user_id').month.min().value_counts().plot()
plt.title('第一次消费会员数和时间折线图')
plt.xlabel('首购时间')
plt.ylabel('会员数')
output_32_1.png
df.groupby('user_id').month.max().value_counts()
2019-08-01    65
2019-09-01    52
2019-07-01    39
2019-10-01    22
2020-01-01    21
2020-02-01    17
2019-11-01    16
2019-12-01     8
2019-03-01     3
2019-06-01     3
2019-05-01     1
Name: month, dtype: int64
df.groupby('user_id').month.max().value_counts().plot()
plt.title('最后一次消费会员数和时间折线图')
plt.xlabel('最后购买时间')
plt.ylabel('会员数')
output_34_1.png
#各会员首次、最后一次消费时间间隔
(df.groupby('user_id')['month'].agg({'num1':'min', 'num2':'max'}).num2-df.groupby('user_id')['month'].agg({'num1':'min', 'num2':'max'}).num1).value_counts()
0 days      177
31 days      24
61 days       6
92 days       6
122 days      6
337 days      5
30 days       4
306 days      3
153 days      3
184 days      3
62 days       2
123 days      2
215 days      2
245 days      2
275 days      1
276 days      1
dtype: int64

说明:
1.用groupby函数将用户分组,并且求月份的最小值、最小值即用户消费行为的第一次消费时间。
2.大部分用户的第一次消费集中在7、8月份,观察用户的最后一次消费时间,将近80%的客户都在首次消费1个月内流失。

数据分析-用户行为中的复购率和回购率分析

数据透视-每位会员各月消费次数

#统计用户消费次数
pivoted_counts=df.pivot_table(index='user_id',columns='month',values='order_dt',aggfunc='count').fillna(0)
columns_month=df.month.dt.date.sort_values().unique()
pivoted_counts.columns=columns_month
pivoted_counts.head()
user_id 2019-03-01 2019-04-01 2019-05-01 2019-06-01 2019-07-01 2019-08-01 2019-09-01 2019-10-01 2019-11-01 2019-12-01 2020-01-01 2020-02-01
vs10000005 2.00 0.00 3.00 0.00 0.00 0.00 0.00 0.00 0.00 1.00 0.00 0.00
vs10000621 6.00 17.00 19.00 20.00 17.00 5.00 2.00 18.00 18.00 21.00 16.00 10.00
vs10000627 0.00 0.00 0.00 0.00 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
vs10000716 0.00 0.00 0.00 0.00 14.00 19.00 24.00 12.00 30.00 15.00 12.00 5.00
vs10000743 1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00

复购率分析

复购率的定义是在某时间窗口内消费两次及以上的用户在总消费用户中占比。这里的时间窗口是月,如果一个用户在同一天下了两笔订单,这里也将他算作复购用户。
消费两次及以上记为1,消费一次记为0,没有消费记为NaN。

pivoted_counts.transf=pivoted_counts.applymap(lambda x:1 if x>1 else np.NaN if x==0 else 0)
pivoted_counts.transf.head()
user_id 2019-03-01 2019-04-01 2019-05-01 2019-06-01 2019-07-01 2019-08-01 2019-09-01 2019-10-01 2019-11-01 2019-12-01 2020-01-01 2020-02-01
vs10000005 1.00 nan 1.00 nan nan nan nan nan nan 0.00 nan nan
vs10000621 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00
vs10000627 nan nan nan nan 1.00 nan nan nan nan nan nan nan
vs10000716 nan nan nan nan 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00
vs10000743 0.00 nan nan nan nan nan nan nan nan nan nan nan
month_counts_reorder_rate=pivoted_counts.transf.sum()/pivoted_counts.transf.count()
plt.plot(month_counts_reorder_rate)
plt.title('每月用户复购率图')
plt.xlabel('时间(月)')
plt.ylabel('百分比')
output_42_1.png

说明:3月至6月新用户加入数量较少,拉高了复购率。在大量新用户加入并流失的8月的复购率较低。而在后期,这时的用户都是大浪淘沙剩下的老客,复购率继续上升。

a,b=plt.subplots(figsize=(10,6))
b.plot(pivoted_counts.transf.count())
b.plot(pivoted_counts.transf.sum())
legends=['消费人数','二次消费以上用户人数']
b.legend(legends)
plt.title('每月消费和二次消费以上用户人数')
plt.xlabel('时间(月)')
plt.ylabel('用户数')
output_44_1.png

回购率分析

回购率是某一个时间窗口内消费的用户,在下一个时间窗口仍旧消费的占比。比如1月消费用户1000,他们中有300个2月依然消费,回购率是30%。

pivoted_amount=df.pivot_table(index='user_id',columns='month',values='order_amount',aggfunc='mean').fillna(0)
columns_month=df.month.dt.date.sort_values().unique()
pivoted_amount.columns=columns_month
pivoted_amount.head()
user_id 2019-03-01 2019-04-01 2019-05-01 2019-06-01 2019-07-01 2019-08-01 2019-09-01 2019-10-01 2019-11-01 2019-12-01 2020-01-01 2020-02-01
vs10000005 25.00 0.00 19.67 0.00 0.00 0.00 0.00 0.00 0.00 80.00 0.00 0.00
vs10000621 414.00 20.00 20.00 20.00 17.65 20.00 20.00 20.00 20.00 20.00 20.00 20.00
vs10000627 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
vs10000716 0.00 0.00 0.00 0.00 20.00 41.84 10.83 15.00 15.33 20.00 20.00 20.20
vs10000743 20.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
#统计会员用户是否回购
pivoted_purchase=pivoted_amount.applymap(lambda x:1 if x>1 else 0)
pivoted_purchase.head()
user_id 2019-03-01 2019-04-01 2019-05-01 2019-06-01 2019-07-01 2019-08-01 2019-09-01 2019-10-01 2019-11-01 2019-12-01 2020-01-01 2020-02-01
vs10000005 1 0 1 0 0 0 0 0 0 1 0 0
vs10000621 1 1 1 1 1 1 1 1 1 1 1 1
vs10000627 0 0 0 0 0 0 0 0 0 0 0 0
vs10000716 0 0 0 0 1 1 1 1 1 1 1 1
vs10000743 1 0 0 0 0 0 0 0 0 0 0 0
def purchase_return(data):
         status = []
         for i in range(11):
             if data[i] >= 1:
                 if data[i + 1] >= 1:
                     status.append(1)
                 else:
                     status.append(0)
             else:
                 status.append(np.NaN)
         status.append(np.NaN)
         return pd.Series(status)
pivoted_purchase_return = pivoted_purchase.apply(purchase_return,axis=1)
pivoted_purchase_return.columns=columns_month
pivoted_purchase_return .head()
user_id 2019-03-01 2019-04-01 2019-05-01 2019-06-01 2019-07-01 2019-08-01 2019-09-01 2019-10-01 2019-11-01 2019-12-01 2020-01-01 2020-02-01
vs10000005 0.00 nan 0.00 nan nan nan nan nan nan 0.00 nan nan
vs10000621 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00 nan
vs10000627 nan nan nan nan nan nan nan nan nan nan nan nan
vs10000716 nan nan nan nan 1.00 1.00 1.00 1.00 1.00 1.00 1.00 nan
vs10000743 0.00 nan nan nan nan nan nan nan nan nan nan nan
pivoted_purchase_return_rate=pivoted_purchase_return.sum()/pivoted_purchase_return.count()
plt.plot(pivoted_purchase_return_rate)
plt.title('12个月内用户回购率图')
plt.xlabel('时间(月)')
plt.ylabel('百分比')
plt.xticks(rotation=90)
output_50_1.png
a,b=plt.subplots(figsize=(10,6))
b.plot(pivoted_purchase_return.count())
b.plot(pivoted_purchase_return.sum())
legends=['每月消费人数','每月回购人数']
b.legend(legends)
plt.title('每月消费和每月回购人数')
plt.xlabel('时间(月)')
plt.ylabel('用户数')
output_51_1.png
a,b=plt.subplots(figsize=(10,6))
b.plot(pivoted_purchase_return_rate)
b.plot(month_counts_reorder_rate)
legends=['每月回购率','每月复购率']
b.legend(legends)
plt.title('每月回购率和每月复购率')
plt.xlabel('时间(月)')
plt.ylabel('百分比')
output_52_1.png

说明:大体上,每月用户的复购率高于回购率,波动性也较强。新用户的回购率在30%左右,和老客差异不大。

数据分析-用户行为中层分析

RFM分层

user_rfm=df.pivot_table(index='user_id',values=['order_dt','order_products','order_amount'],aggfunc={'order_dt':'max','order_products':'count','order_amount':'sum'})
user_rfm.head()
user_id order_amount order_dt order_products
vs10000005 189 2019-12-27 6
vs10000621 5704 2020-02-28 169
vs10000627 0 2019-07-23 2
vs10000716 2616 2020-02-28 131
vs10000743 20 2019-03-15 1
user_rfm['period']=(user_rfm.order_dt.max()-user_rfm.order_dt)/np.timedelta64(1,'D')
user_rfm=user_rfm.rename(columns={'period':'R','order_products':'F','order_amount':'M'})
user_rfm.head()
user_id M order_dt F R
vs10000005 189 2019-12-27 6 63.00
vs10000621 5704 2020-02-28 169 0.00
vs10000627 0 2019-07-23 2 220.00
vs10000716 2616 2020-02-28 131 0.00
vs10000743 20 2019-03-15 1 350.00
#定义分层函数
def rfm_func(x):
    level=x.apply(lambda x:'1' if x>=0 else '0')
    label=level.R+level.F+level.M
    d={'111':'高价值客户','011':'重点保持客户',
       '101':'重点发展客户','001':'重点挽留客户',
      '110':'一般价值客户','010':'一般保持客户',
     '100':'一般发展客户','000':'潜在客户'}
    result=d[label]
    return result
user_rfm['label']=user_rfm[['R','F','M']].apply( lambda x:x-x.mean()).apply(rfm_func,axis=1)
user_rfm.head()
user_id M order_dt F R label
vs10000005 189 2019-12-27 6 63.00 重点挽留客户
vs10000621 5704 2020-02-28 169 0.00 重点保持客户
vs10000627 0 2019-07-23 2 220.00 一般发展客户
vs10000716 2616 2020-02-28 131 0.00 重点保持客户
vs10000743 20 2019-03-15 1 350.00 一般发展客户
user_rfm.groupby('label').count()
label M order_dt F R
一般保持客户 3 3 3 3
一般发展客户 146 146 146 146
潜在客户 63 63 63 63
重点保持客户 24 24 24 24
重点发展客户 2 2 2 2
重点挽留客户 2 2 2 2
高价值客户 7 7 7 7
user_rfm.groupby('label').sum()
label M F R
一般保持客户 352 34 98.00
一般发展客户 2653 272 28793.00
潜在客户 1723 125 6377.00
重点保持客户 32494 1416 846.00
重点发展客户 2091 5 575.00
重点挽留客户 2919 9 165.00
高价值客户 3856 152 1429.00
from matplotlib import font_manager as fm #字体管理器
from matplotlib import cm#
proptease = fm.FontProperties()
proptease.set_size('medium')

labelindex =user_rfm.groupby('label').count().index
labelvalues =user_rfm.groupby('label')['M'].count().tolist()
s = pd.Series(labelvalues, index=labelindex )
labels = s.index
sizes = s.values

explode = (0,0,0,0,0.1,0.1,0.2)  # only "explode" the 1st slice
fig, axes = plt.subplots(1,2,figsize=(10,6))
ax1,ax2 = axes.ravel()#结合ravel()函数列出所有子图

colors = cm.rainbow(np.arange(len(sizes))/len(sizes))# # 随机生成颜色
# patches:饼片。texts:分类标签的文本列表。autotexts:百分比部分的文本列表
patches, texts, autotexts = ax1.pie(sizes, labels=labels, autopct='%1.0f%%',explode=explode,
shadow=False, startangle=170, colors=colors, labeldistance=1.2,pctdistance=1.05, radius=0.4)
ax1.axis('equal')#将饼图显示为正圆形
plt.setp(texts, fontproperties=proptease)

# 设置百分比文本样式
for i in autotexts:
    i.set_size('large')
ax1.set_title('用户分层结构饼状图', loc='center')
ax2.axis('off')#关闭所有坐标轴线、刻度标记和标签
ax2.legend(patches, labels, loc='center left',fontsize=10)
plt.tight_layout()#tight_layout会自动调整子图参数,使之填充整个图像区域
output_61_0.png

分析:从用户分层结果可知,一般发展客户占了较大的比重,为59%,潜在客户排第二位,占比26%。

总分层分析

按照用户的消费行为,简单划分成几个维度:新用户、活跃用户、不活跃用户、回流用户。
新用户(new)的定义是第一次消费。
活跃用户(active)即老客,在某一个时间窗口内有过消费。
不活跃用户(unactive)则是时间窗口内没有消费过的老客。
回流用户(return)是在上一个窗口中没有消费,而在当前时间窗口内有过消费。
以上的时间窗口都是按月统计。

def active_status(data):
    status = []
    for i in range(12):
        #若本月没有消费
        if data[i] == 0:
            if len(status) > 0:
                if status[i-1] == 'unreg': #未注册
                    status.append('unreg')
                else:
                    status.append('unactive')
            else:
                status.append('unreg')
          #若本月有消费      
        else:
            if len(status) == 0:
                status.append('new')
            else:
                if status[i-1] == 'unactive':
                    status.append('return')
                elif status[i-1] == 'unreg':
                    status.append('new')
                else:
                    status.append('active')
    return pd.Series(status)
pivoted_purchase_status = pivoted_purchase.apply( lambda x:active_status(x),axis=1)
pivoted_purchase_status.columns=columns_month
pivoted_purchase_status .head()
user_id 2019-03-01 2019-04-01 2019-05-01 2019-06-01 2019-07-01 2019-08-01 2019-09-01 2019-10-01 2019-11-01 2019-12-01 2020-01-01 2020-02-01
vs10000005 new unactive return unactive unactive unactive unactive unactive unactive return unactive unactive
vs10000621 new active active active active active active active active active active active
vs10000627 unreg unreg unreg unreg unreg unreg unreg unreg unreg unreg unreg unreg
vs10000716 unreg unreg unreg unreg new active active active active active active active
vs10000743 new unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive unactive
pivoted_status_counts=pivoted_purchase_status.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
pivoted_status_counts
2019-03-01 2019-04-01 2019-05-01 2019-06-01 2019-07-01 2019-08-01 2019-09-01 2019-10-01 2019-11-01 2019-12-01 2020-01-01 2020-02-01
active nan 7.00 9 16.00 20.00 18.00 11 12 15 14 16 10
new 13.00 2.00 8 9.00 17.00 17.00 10 9 6 7 7 1
return nan nan 1 nan nan nan 4 5 1 4 2 3
unactive nan 6.00 5 7.00 12.00 31.00 51 59 69 73 80 92
plt.plot(pivoted_status_counts.T)
plt.title('每月各种用户类型占比折线图')
plt.legend(pivoted_status_counts.index)
plt.xlabel('时间(月)')
plt.ylabel('用户数')
output_66_1.png

分析:黑色的不活跃用户占了较大的比重。红色的活跃用户较稳定,其与紫色的回流用户相加大抵是本月消费人数。

回流用户及活跃用户分析

return_rate=pivoted_status_counts.apply(lambda x:x/x.sum(),axis=1)
plt.plot(return_rate.loc[['active','return'],].T)
plt.title('每月活跃用户、回流用户占比')
plt.xlabel('时间(月)')
plt.ylabel('百分数')
plt.xticks(rotation=90)
output_69_1.png

说明:结合回流用户和活跃用户看,在后期的消费用户中,70%是回流用户,30%是活跃用户,整体质量还好。

数据分析-用户质量分析

总质量分析

user_amount=df.groupby('user_id').order_amount.sum().sort_values().reset_index()
user_amount['amount_cumsum']=user_amount.order_amount.cumsum()
user_amount.tail()
user_id order_amount amount_cumsum
242 vs10000716 2616 29735
243 vs10000775 2730 32465
244 vs30026748 3296 35761
245 vs30029475 4623 40384
246 vs10000621 5704 46088
amount_total=user_amount.amount_cumsum.max()
user_amount['prop'] = user_amount.amount_cumsum.apply(lambda x:x/amount_total)
plt.plot(user_amount.prop )
plt.title('用户累计贡献金额百分比')
plt.xlabel('人数')
plt.ylabel('百分数')
output_74_1.png

说明:此次数据集用户总共247人,可见其中47人(约占总人数的19%)贡献了超过80%的销售金额。

数据分析-用户生命周期分析

第一生命周期

#各会员首次、最后一次消费时间间隔
order_dt_min=df.groupby('user_id').order_dt.min()
order_dt_max=df.groupby('user_id').order_dt.max()
life_time=(order_dt_max-order_dt_min).reset_index()
life_time.head()
user_id order_dt
0 vs10000005 273 days
1 vs10000621 351 days
2 vs10000627 1 days
3 vs10000716 238 days
4 vs10000743 0 days
life_time.describe()
order_dt
count 247
mean 32 days 03:59:01.700404
std 73 days 19:15:10.251372
min 0 days 00:00:00
25% 0 days 00:00:00
50% 1 days 00:00:00
75% 13 days 00:00:00
max 351 days 00:00:00

分析:由描述可知,所有用户的平均生命周期是32天,中位数是1天,即存在50%的客户首次消费即最后一次消费。
最大值351天,即本数据集的总天数,说明存在从开始到最后都消费的高质量用户。

((order_dt_max-order_dt_min)/np.timedelta64(1,'D')).hist(bins=15)
plt.title('用户生命周期直方图')
plt.xlabel('天数')
plt.ylabel('人数')
output_81_1.png

消费两次以上的用户生命周期

life_time['life_time']=life_time.order_dt/np.timedelta64(1,'D')
life_time[life_time.life_time>0].life_time.hist(bins=15)#排除仅消费一次的客户
plt.title('二次消费以上用户生命周期直方图')
plt.xlabel('天数')
plt.ylabel('人数')
output_83_1.png
life_time[life_time.life_time>0].life_time.describe()
count   155.00
mean     51.26
std      87.84
min       1.00
25%       2.00
50%       7.00
75%      53.50
max     351.00
Name: life_time, dtype: float64

分析:二次消费以上用户生命周期为51天,略高于总体。从策略上看,用户首次消费后应该引导其再次消费。

数据分析-用户留存率分析

#留存率指用户在第一次消费后,有多少比率进行第二次消费。和回流率的区别是留存倾向于计算第一次消费,并且有多个时间窗口。
user_purchase_retention=pd.merge(left=df,right=order_dt_min.reset_index(),how='inner',on='user_id',suffixes=('','_min'))
user_purchase_retention['date_diff']=(user_purchase_retention.order_dt-user_purchase_retention.order_dt_min)/np.timedelta64(1,'D')
bin=[0,30,60,90,120,150,180,365]
user_purchase_retention['date_diff_bin']=pd.cut(user_purchase_retention['date_diff'],bins=bin)
user_purchase_retention.head(10)
user_id order_dt order_products order_amount month order_dt_min date_diff date_diff_bin
vs30033073 2020-01-17 1 20 2020-01-01 2019-09-23 116.00 (90, 120]
vs30033073 2019-11-29 2 20 2019-11-01 2019-09-23 67.00 (60, 90]
vs30033073 2019-11-13 2 20 2019-11-01 2019-09-23 51.00 (30, 60]
vs30033073 2019-12-24 2 20 2019-12-01 2019-09-23 92.00 (90, 120]
vs30033073 2019-10-29 2 20 2019-10-01 2019-09-23 36.00 (30, 60]
vs30033073 2020-01-07 2 20 2020-01-01 2019-09-23 106.00 (90, 120]
vs30033073 2019-12-09 2 20 2019-12-01 2019-09-23 77.00 (60, 90]
vs30033073 2020-01-06 1 20 2020-01-01 2019-09-23 105.00 (90, 120]
vs30033073 2019-11-01 2 20 2019-11-01 2019-09-23 39.00 (30, 60]
vs30033073 2019-10-21 2 20 2019-10-01 2019-09-23 28.00 (0, 30]
pivoted_retention=user_purchase_retention.pivot_table(index='user_id',columns='date_diff_bin',values='order_amount',aggfunc=sum,dropna=False)
pivoted_retention.head()
user_id (0,30] (30,60] (60,90] (90,120] (120,150] (150,180] (180,365]
vs10000005 nan 59 nan nan nan nan 80
vs10000621 240 300 420 400 200 40 1700
vs10000627 0 nan nan nan nan nan nan
vs10000716 280 795 240 220 440 280 341
vs10000743 nan nan nan nan nan nan nan
pivoted_retention.mean()
date_diff_bin
(0, 30]       52.70
(30, 60]     148.62
(60, 90]     171.52
(90, 120]    307.59
(120, 150]   112.90
(150, 180]   111.60
(180, 365]   700.36
dtype: float64
pivoted_retention.transf=pivoted_retention.fillna(0).applymap(lambda x:1 if x>0 else 0)
(pivoted_retention.transf.sum()/pivoted_retention.transf.count()).plot.bar()
plt.title('各时间段的用户留存率')
plt.xlabel('时间跨度(天)')
plt.ylabel('百分数')
output_90_2.png

分析:第一个月的留存率约超过17.5%,第二个月下降至15%,之后几个月稳定在6%左右,说明后面几个月流失率较大 。

数据分析-决策分析

平均购买周期:用户两次消费行为的时间间隔。

def diff(group):
    d=group.date_diff.shift(-1)-group.date_diff
    return d
last_diff=user_purchase_retention.sort_values("order_dt").reset_index().groupby('user_id').apply(diff)
last_diff.head(10)
user_id         
vs10000005  31       0.00
            34      42.00
            158      1.00
            160      0.00
            161    230.00
            1715      nan
vs10000621  2        0.00
            3       11.00
            22       1.00
            26       1.00
Name: date_diff, dtype: float64
last_diff.describe()
count   1766.00
mean       4.50
std       14.03
min        0.00
25%        1.00
50%        1.00
75%        4.00
max      230.00
Name: date_diff, dtype: float64

说明:可知用户的平均消费间隔时间是4.5天。想要召回用户,在4.5天左右的消费间隔是比较好的。

last_diff.hist(bins=15)
plt.title('用户平均购买周期直方图')
plt.xlabel('时间跨度(天)')
plt.ylabel('百分数')
output_96_1.png

说明:典型的长尾分布,大部分用户的消费间隔比较短。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容