数据来源 CDNow 网站的用户购买明细,通过各个指标对用户行为进行分析,可以更清楚了解用户行为习惯,为进一步制定营销策略提供依据。

具体指标包括:

  • 户消费趋势分析
  • 用户个体消费分析
  • 用户消费行为分析
  • 复购率和回购率分析
  • 留存率分析

一、理解数据

本数据集共有 6 万条左右数据,数据为 CDNow 网站 1997年1月至1998年6月的用户行为数据,共计 4 列字段,分别是:

  • user_id: 用户ID
  • order_dt: 购买日期
  • order_products: 购买产品数
  • order_amount: 购买金额

二、清洗数据

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.rcParams[\'font.sans-serif\']=[\'SimHei\']
plt.rcParams[\'axes.unicode_minus\']=False
plt.style.use(\'ggplot\')

1. 数据加载

columns = [\'user_id\', \'order_dt\', \'order_products\', \'order_amount\']
# 将 order_dt 转化为日期数据类型格式
dateparse = lambda dates: pd.datetime.strptime(dates,\'%Y%m%d\')
df = pd.read_table(r\'C:\Users\86134\Desktop\CDNOW_master.txt\',
                   names = columns,parse_dates=[\'order_dt\'],
                   sep = \'\s+\',date_parser=dateparse
                    )

3.数据探索

print(df.info())
print(\'-\'*30)
print(df.isnull().sum())
print(\'-\'*30)
print(df.describe())
print(\'-\'*30)
print(df.head())
print(\'-\'*30)
print(df.tail())
print(\'-\'*30)

输出

<class \'pandas.core.frame.DataFrame\'>
RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
user_id           69659 non-null int64
order_dt          69659 non-null datetime64[ns]
order_products    69659 non-null int64
order_amount      69659 non-null float64
dtypes: datetime64[ns](1), float64(1), int64(2)
memory usage: 2.1 MB
None
------------------------------
user_id           0
order_dt          0
order_products    0
order_amount      0
dtype: int64
------------------------------
            user_id  order_products  order_amount
count  69659.000000    69659.000000  69659.000000
mean   11470.854592        2.410040     35.893648
std     6819.904848        2.333924     36.281942
min        1.000000        1.000000      0.000000
25%     5506.000000        1.000000     14.490000
50%    11410.000000        2.000000     25.980000
75%    17273.000000        3.000000     43.700000
max    23570.000000       99.000000   1286.010000
------------------------------
   user_id   order_dt  order_products  order_amount
0        1 1997-01-01               1         11.77
1        2 1997-01-12               1         12.00
2        2 1997-01-12               5         77.00
3        3 1997-01-02               2         20.76
4        3 1997-03-30               2         20.76
------------------------------
       user_id   order_dt  order_products  order_amount
69654    23568 1997-04-05               4         83.74
69655    23568 1997-04-22               1         14.99
69656    23569 1997-03-25               2         25.74
69657    23570 1997-03-25               3         51.12
69658    23570 1997-03-26               2         42.96
------------------------------

通过数据探索我们发现 – 大部分订单只购买了少量商品 (平均 2.4), 有一定极值干扰; – 用户消费的金额比较稳定, 平均消费 35 元, 中位数在 35 元, 有一定极值干扰; – 数据呈右偏分布; – 没有空缺数据,可以直接分析,但考虑到是按月分析,所以将日期进行解析(实际业务是否按月分析,取决于消费频率) 。

# 解析日期
df[\'oreder_dt\'] = pd.to_datetime(df.order_dt, format=\'%Y%m%d\')
df[\'month\'] = df.order_dt.values.astype(\'datetime64[M]\')

三、用户消费趋势分析(按月)

  • 每月的产品购买数量
  • 每月的消费总金额
  • 每月的消费次数
  • 每月的消费人数

1.每月的产品购买数量

grouped_momnth = df.groupby(\'month\')
plt.figure(1, figsize=(10, 4))
plt.title(\'每月用户购买张数\')
plt.ylabel(\'CD碟数(张)\')
grouped_momnth.order_products.sum().plot()
plt.show()

 

 

 

从图中可以看到,销量在前几个月异常高涨,并在3月达到最高峰,后续销量较为稳定,且有轻微下降趋势。

2.每月的消费金额

plt.figure(1, figsize=(10, 4))
plt.title(\'每月销售额\')
plt.ylabel(\'销售额\')
grouped_momnth.order_amount.sum().plot()
plt.show()

 

 

 

由图可以看到,消费金额也一样呈现早期销售多,后期平稳下降趋势,而且前三月数据都呈现出异常状态,为什么呈现这样的原因呢?我们可以假设前三个月有促销活动,或者用户本身出了问题,早期用户有异常值。但这里只有消费数据,因此不能做出判断。

3.每月消费次数

plt.figure(1, figsize=(10, 4))
plt.title(\'每月订单数\')
plt.ylabel(\'订单数\')
grouped_momnth.user_id.count().plot()
plt.show()

 

 

 

前三个月订单数在 10000 笔左右,后续月份的平均消费订单数则在 2500 笔左右。

4.每月消费人数

plt.figure(1, figsize=(10, 4))
plt.title(\'每月消费人数\')
plt.ylabel(\'人数\')
grouped_momnth.user_id.apply(lambda x: len(x.drop_duplicates())).plot()
plt.show()

 

 

 

每月消费人数低于每月消费次数,但差异不大。
前三个月每月消费人数在 8000~10000 之间,后续月份,平均消费人数在 2000 人不到。

四、用户个体消费分析

  • 用户消费金额,消费次数的描述统计
  • 用户消费金额和购买数量散点图
  • 用户消费分布图
  • 用户累计消费金额的占比(百分之多少的用户占了百分之多少的消费)

1.用户消费金额,消费次数的描述统计

grouped_user = df.groupby(\'user_id\')

 

从用户角度

  • 用户数量:23570,每位用户平均购买 7 张 CD,但是中位数值只有3,且有狂热用户购买了1033 张。平均值大于中位数,是右偏分布,说明小部分用户购买了大量的 CD。

从消费金额角度

  • 用户平均消费 106 元,中位值只有 43,且有土豪用户消费 13990,结合分位数和最大值看,平均数仅和 75 分位接近,肯定存在小部分的高频消费用户。
plt.figure(figsize=(12,4))
plt.subplot(121)
plt.scatter(x = \'order_amount\', y = \'order_products\',data=df)
plt.xlabel(\'每笔订单消费金额\')
plt.ylabel(\'每笔订单购买数量\')

plt.subplot(122)
plt.scatter(x = \'order_amount\',y = \'order_products\', 
            data = grouped_user.sum()) 
plt.xlabel(\'每位用户消费金额\')
plt.ylabel(\'每位用户购买数量\')
plt.show()

 

 

 

从每笔订单的散点图观察

  • 订单消费金额和订单商品有规律性,每个商品均价 10元,且订单极值较少,超出 1000 的不多,所以不是造成异常波动的原因。

从每位用户的消费散点图观察

  • 用户比较健康,且线性关系比订单更强,由于这是 CD 网站的销售数据,商品较为单一,金额和商品的关系因此呈线性关系,离群点不多。

3.用户消费分布图

为了更好的观察消费能力极强的用户,因为数量不多,所以用直方图

plt.figure(figsize=(12, 4))
plt.subplot(121)
ax = grouped_user.order_amount.sum().hist(bins=50)
ax.set_xlabel(\'金额(美元)\')
ax.set_ylabel(\'用户人数\')
ax.set_xlim(0, 2000)
ax.set_title(\'用户消费金额分布图\')

plt.subplot(122)
ax1 = grouped_user.order_products.sum().hist(bins = 50)

ax1.set_xlabel(\'CD 数(张)\')
ax1.set_ylabel(\'用户人数\')
ax1.set_xlim(0, 150)
ax1.set_title(\'购买 CD 数分布图\')
plt.show()

 

 

 

从直方图可知,用户消费金额,绝大部分呈现集中趋势,大部分购买CD数20张内,高消费用户在图上几乎看不到,这是符合消费行为的行业规律。

4.用户累计消费金额的占比

user_cumsum = grouped_user.sum().sort_values(\'order_amount\').apply(lambda x:x.cumsum())
user_cumsum
user_cumsum = grouped_user.sum().sort_values(\'order_amount\').apply(lambda x:x.cumsum() / x.sum())
user_cumsum.reset_index().order_amount.tail()
# 输出
23565    0.985405
23566    0.988025
23567    0.990814
23568    0.994404
23569    1.000000
Name: order_amount, dtype: float64
user_cumsum = grouped_user.sum().sort_values(\'order_amount\').apply(lambda x:(x.cumsum() / x.sum())*100)
user_cumsum.reset_index().order_amount.plot()
plt.title(\'用户累计消费金额占比\')
plt.xlabel(\'人数\')
plt.ylabel(\'百分比 %\')
plt.show()

 

 

 

通过分析累计销售额占比,从图中不难看出用户消费行为基本符合二八定律,80% 的用户贡献了 25% 的消费金额,而 60% 的消费由前 5000 名用户贡献。所以只要维护了这5000 名用户,就能完成 60% 的KPI。

五、用户消费行为

  • 用户第一次消费(首购)时间
  • 用户最后一次消费时间
  • 用户分层
    • RFM (RFM模型是衡量客户价值和客户创利能力的重要工具和手段)
    • 新、老、活跃、回流、流失

 

  • 用户购买周期(按订单)
    • 用户消费周期描述
    • 用户消费周期分布
  • 用户生命周期(按第一次&最后一次消费)
    • 用户生命周期描述
    • 用户生命周期分布

1.用户首购时间

grouped_user.min().month.value_counts()
# 输出
1997-02-01    8476
1997-01-01    7846
1997-03-01    7248
Name: month, dtype: int64
grouped_user.min().order_dt.value_counts().plot() # 首购
plt.show()

 

 

 

 

2.用户最后一次购买时间

grouped_user.month.max().value_counts()
# 输出
1997-02-01    4912
1997-03-01    4478
1997-01-01    4192
1998-06-01    1506
1998-05-01    1042
1998-03-01     993
1998-04-01     769
1997-04-01     677
1997-12-01     620
1997-11-01     609
1998-02-01     550
1998-01-01     514
1997-06-01     499
1997-07-01     493
1997-05-01     480
1997-10-01     455
1997-09-01     397
1997-08-01     384
Name: month, dtype: int64
grouped_user.max().order_dt.value_counts().plot() # 最后一次消费
plt.show()

 

 

 

通过以上两个维度观察,可以看出

  • 用户第一次购买分布,集中在前三个月,其中,在 2 月 11 日至 2 月 25 日有一次剧烈波动。
  • 用户最后一次购买的分布比第一次分布广,但是大部分最后一次购买也集中在前三个月,说明忠诚用户较少,随着时间的递增,最后一次购买数在递增,消费呈现流失上升的趋势,所以可以推测,这份数据选择的是前三个月消费的用户在后面18个月的跟踪记录数据,前三个月消费金额和购买数量的异常趋势获得解释。

3.用户分层

3.1 构建RFM 模型

  • Recency Frequency Monetary
rfm = df.pivot_table(index = \'user_id\',
                    values = [\'order_products\', \'order_amount\', \'order_dt\'],
                    aggfunc = {\'order_dt\':\'max\',
                               \'order_amount\':\'sum\',
                               \'order_products\':\'sum\'
                              })
rfm.head()

 

 

 

 

rfm[\'R\'] = -(rfm.order_dt - rfm.order_dt.max()) / np.timedelta64(1, \'D\')
rfm.rename(columns = {\'order_products\': \'F\', \'order_amount\':\'M\'},
                 inplace=True)
rfm.head()

 

 

def rfm_func(x):
    level = x.apply(lambda x:\'1\' if x>=1 else \'0\')
    label = level.R + level.F + level.M
    d = {
        \'111\':\'重要价值客户\', 
        \'011\':\'重要保持客户\',
        \'101\':\'重要挽留客户\',
        \'001\':\'重要发展客户\',
        \'110\':\'一般价值客户\',
        \'010\':\'一般保持客户\',
        \'100\':\'一般挽留客户\',
        \'000\':\'一般发展客户\'
        }
    result = d[label]
    return result

rfm[\'label\'] = rfm[[\'R\', \'F\', \'M\']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.head()

 

 

 

 

rfm.groupby(\'label\').sum()

 

 

 

 

for label,gropued in rfm.groupby(\'label\'):
    x= gropued[\'F\']
    y = gropued[\'R\']

    plt.scatter(x,y,label = label) # 利用循环绘制函数
plt.legend(loc=\'best\') # 图例位置
plt.xlabel(\'Frequency\')
plt.ylabel(\'Recency\')
plt.show()

 

 

 

从 RFM 分层可知,大部分用户为重要保持客户,但这是因为极值存在,所以 FRM 的划分应按照业务为准划分

  • 尽量用小部分的用户覆盖大部分的额度
  • 不要为了数据好看而划分等级

 

3.2 按新、活跃、回流、流失分层用户

# 通过每月是否消费来划分用户
pivoted_counts = df.pivot_table(index = \'user_id\',
                                columns = \'month\',
                                values = \'order_dt\',
                                aggfunc = \'count\').fillna(0)
pivoted_counts.columns = df.month.sort_values().astype(\'str\').unique()
pivoted_counts.head()

 

 

 

 

df_purchase = pivoted_counts.applymap(lambda x: 1 if x> 0 else 0)
df_purchase.tail()

 

 

 

 

def active_status(data):
    status = []
    for i in range(18): 

        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,df_purchase.columns)

若本月没有消费

  • 若之前未注册,则依旧未注册
  • 若之前有消费,则为流失/为活跃
  • 其他情况,未注册

若本月消费

  • 若是第一次消费,则为新用户
  • 如果之前有过消费,上个月为不活跃,则为回流
  • 如果上个月未注册,则为新用户
  • 除此之外,为活跃
purchase_states = df_purchase.apply(active_status,axis = 1)
purchase_states.tail()

 

 

 

 

purchase_states_ct = purchase_states.replace(\'unreg\',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_states_ct

 

 

 

unreg 状态排除掉,是未来才成为新用户,作为不同分呈用户每月统计量。

# 转置后方便观察
purchase_states_ct.fillna(0).T

 

 

 

 

# 绘制面积图
purchase_states_ct.fillna(0).T.plot.area(figsize = (12, 6))
plt.show()

 

 

 

由面积图,蓝色和灰色区域占大面积,可以不看,因为这只是某段时间消费过的用户的后续行为。其次红色代表的活跃用户非常稳定,是属于核心用户,以及紫色的回流用户,这两个分层相加,就是消费用户人数占比(后期没用新客)

3.3回流用户占比

plt.figure(figsize=(20, 4))
rate = purchase_states_ct.fillna(0).T.apply(lambda x: x/x.sum())
plt.plot(rate[\'return\'],label=\'return\')
plt.plot(rate[\'active\'],label=\'active\')
plt.legend()
plt.show()

 

 

 

 

  • 回流用户比:某个时间段内回流用户在总用户中的占比
    • 由图可知,用户每月回流用户比占 5% ~ 8% 之间,有下降趋势,说明客户有流失倾向。

 

  • 回流用户率:上月有多少不活跃用户在本月消费
    • 由于这份数据的不活跃用户量基本不变,所以这里的回流率,也近似等于回流比

 

  • 活跃用户比:某个时间段内活跃用户在总用户中的占比。
    • 活跃用户的占比在 3% ~ 5%间,下降趋势更显著,活跃用户可以看作连续消费用户,忠诚度高于回流用农户。

结合活跃用户和回流用户看,在后期的消费用户中,60%是回流用户,40%是活跃用户,整体用户质量相对不错。也进一步说明前面用户消费行为分析中的二八定律,反应了在消费领域中,狠抓高质量用户是不变的道理。

4.用户购买周期

# 订单时间间隔
order_diff = grouped_user.apply(lambda x:x.order_dt - x.order_dt.shift())
order_diff.head(10)

 

 

 

 

order_diff.describe()

 

 

 

 

# 订单周期分布图
(order_diff / np.timedelta64(1, \'D\')).hist(bins = 20)
plt.show()

 

 

 

  • 订单周期呈指数分布
  • 用户的平均购买周期是 68 天
  • 绝大部分用户的购买周期低于 100 天
  • 用户生命周期图是典型的长尾图,大部分用户的消费间隔确实比较短。不妨将时间召回点设为消费后立即赠送优惠券,消费后10天询问用户CD怎么样,消费后30天提醒优惠券到期,消费后60天短信推送。

5.用户生命周期

# 最后一次购买的时间减去首购时间
user_life = grouped_user.order_dt.agg([\'min\', \'max\'])
user_life.head()

 

 

 

 

# 只消费过一次的用户占比
(user_life[\'min\'] == user_life[\'max\']).value_counts().plot.pie()
plt.show()
(user_life[\'max\'] - user_life[\'min\']).describe()

 

 

 

通过描述可知,用户平均生命周期 134 天,比预想高,但是平均数不靠谱,中位数 0 天,大部分用户第一次消费也是最后一次,这批属于低质量用户,而最大的是 544 天,几乎是数据集的总天数,这用户属于核心用户。

因为数据中的用户都是前三个月第一次消费,所以这里的生命周期代表的是1月~3月用户的生命周期。因为用户会持续消费,这段时间过后还会继续消费,用户的平均生命周期会增长。

plt.figure(figsize=(20, 4))
plt.subplot(121)
((user_life[\'max\'] - user_life[\'min\']) / np.timedelta64(1, \'D\')).hist(bins = 15)
plt.title(\'二次消费以上用户的生命周期直方图\')
plt.xlabel(\'天数\')
plt.ylabel(\'人数\')

# 过滤生命周期为0 的
plt.subplot(122)
u_l = ((user_life[\'max\'] - user_life[\'min\']).reset_index()[0] / np.timedelta64(1, \'D\'))
u_l[u_l > 0].hist(bins = 40)
plt.title(\'二次消费以上用户的生命周期直方图\')
plt.xlabel(\'天数\')
plt.ylabel(\'人数\')
plt.show()

 

 

 

通过两图对比看出,过滤掉周期为 0 的用户后,图像呈双峰结构,虽然还是有不少用户生命周期趋于 0 天,但是相比第一幅图,靠谱多了。部分低质用户,虽然消费两次,但还是不能持续消费,要想提高用户转化率,应该用户首次消费 30 天内尽量引导,少部分用户集中在 50 – 300 天,属于普通用户,忠诚度一般。集中在 400 天以后的,是高质量用户了,后期人数还在增加,这批用户已经属于核心用户了,忠诚度极高,尽量维护这批用户的利益。

# 消费两次以上用户平均生命周期
u_l[u_l > 0].mean()

# 输出
276.0448072247308

消费两次以上的用户平均生命周期是 276 天,远高于总体,所以如何在用户首次消费后引导其进行多次消费,可以有效提高用户生命周期。

版权声明:本文为tianshangxing原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/tianshangxing/p/14455639.html