2021-03-02

用户消费行为分析

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

%matplotlib inline
plt.style.use('ggplot')
columns = ['userid', 'datetime', 'products', 'amounts']
df = pd.read_table(r'C:\Users\asus\Documents\CDNow\CDNOW_master.txt',names=columns, sep='\s+')
df.head()
df.info()

RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
userid      69659 non-null int64
datetime    69659 non-null int64
products    69659 non-null int64
amounts     69659 non-null float64
dtypes: float64(1), int64(3)
memory usage: 2.1 MB

1.数据清洗

# 例如19970101,%Y匹配前四位数字1997,如果y小写只匹配两位数字97,%m匹配01,%d匹配01。
# 另外,小时是%h,分钟是%M,注意和月的大小写不一致,秒是%s。若是1997-01-01这形式,则是%Y-%m-%d,以此类推

df['datetime'] = pd.to_datetime(df['datetime'], format='%Y%m%d')
df['month'] = df['datetime'].values.astype('datetime64[M]')
df.head()
df.describe()

对用户特征进行整体初步分析:

  • 从数据的统计描述信息中可以看出,用户每个订单平均购买2.41个商品,每个订单平均消费35.89元。
  • 人均购买CD金额在35.89元,而中位数是25.98元,且订单最大值是99,说明存在极值干扰,许多销售行业都是类似这种分布,小额较多,大额较少,收入来源很大一部分来自大额,也就是二八法则。

2.用户总体消费趋势分析

plt.rcParams['font.sans-serif']=['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号

# 设置图的大小,添加子图
plt.figure(figsize=(20,15))

# 每月的型销售额
plt.subplot(221)  # 将画布分为2行2列,现在绘制第一块子图
df.groupby('month')['amounts'].sum().plot(fontsize=24)
plt.title('总销售额', fontsize=24)

# 每月的消费次数
plt.subplot(222)
df.groupby('month')['datetime'].count().plot(fontsize=24)
plt.title('消费次数', fontsize=24)


# 每月的销量
plt.subplot(223)
df.groupby('month')['products'].sum().plot(fontsize=24)
plt.title('总销量', fontsize=24)

# 每月的消费人数
plt.subplot(224)
df.groupby('month')['userid'].apply(lambda x:len(x.unique())).plot(fontsize=24)
plt.title('消费人数', fontsize=24)
  • 四个折线图整体趋势基本一致,可以看出,可以看出来,1997年前3个月的销量特别高,随之而来的销售额也是暴涨,在3月份之后骤然下降,接近平稳。
  • 为什么会呈现这个原因呢?我们假设是用户身上出了问题,早期时间段的用户中有异常值,第二假设是各类促销营销。
  • 另一方面,在2月到3月这段期间,可以发现消费人数稍有下降,但总销量与总销售额却依然上升,是不是说明3月份的用户中有我们需要重点发展的高价值客户呢?

3.用户消费金额和次数统计及分布

group_user = df.groupby('userid').sum()  #datetime和month属于时间数据类型,不在计算范围内
group_user.describe()
  • 从用户角度看,每位用户平均购买7张CD,最多的用户购买了1033张。用户的平均消费金额(客单价)106元,标准差是240,结合分位数和最大值看,平均值才和75%分位数接近,肯定存在小部分的高额消费用户,这也符合二八法则。
# 创建用户消费金额和次数的散点分布图绘制用户的散点图,用户比较健康而且规律性很强。
# 因为这是CD网站的销售数据,商品比较单一,金额和商品量的关系也因此呈线性分布

group_user.query('amounts < 4000').plot.scatter(x='amounts', y='products')
  • 绘制用户的散点图,用户比较健康而且规律性很强。因为这是CD网站的销售数据,商品比较单一,金额和商品量的关系也因此呈线性分布

4.用户消费金额分布

group_user['amounts'].plot.hist(bins=20) # 极值是14000,将其分成20组,每个间距700
  • 用户的消费呈集中趋势,出现个别极值干扰,根据以上图表不能看出总体消费趋势,应缩小范围,如图当中,大部分消费用户的消费金额在0-800之间
group_user.query('amounts < 800')['amounts'].plot.hist(bins=20)

根据上图看出:

  • 大部分的用户消费都不高,近半数的用户消费金额在40元以内,而200元以上的高消费群体极少
  • 虽然有极端数据干扰,但是大部分的用户还是集中在比较低的消费档次
  • 大部分用户的消费能力确实不高,绝大部分呈现集中在很低的消费档次。高消费用户在图上几乎看不到
group_user.query('products < 100')['products'].plot.hist(bins=20)

大部分用户购买CD的数量都是在3张以内,购买大量CD的用户数量并不多

5.用户购买周期分析

用户购买周期描述

user_diff = df.groupby('userid').apply(lambda x : x['datetime'] - x['datetime'].shift())  #将userid分组后,将购买日期错位相减 
user_diff.head()

userid   
1       0       NaT
2       1       NaT
        2    0 days
3       3       NaT
        4   87 days
Name: datetime, dtype: timedelta64[ns]

表格显示每个用户每次消费的时间间隔

user_diff.describe()
count                      46089
mean     68 days 23:22:13.567662
std      91 days 00:47:33.924168
min              0 days 00:00:00
25%             10 days 00:00:00
50%             31 days 00:00:00
75%             89 days 00:00:00
max            533 days 00:00:00
Name: datetime, dtype: object
  • 用户的平均销售周期为68天,间隔最长的是533天。想要召回用户,在60天左右的消费间隔是比较好的
  • 绝大部分用户的消费周期都低于100天

用户购买周期分布

plt.figure(figsize=(15,5))
(user_diff / np.timedelta64(1, 'D')).hist(bins=20)
plt.xlabel('购买周期', fontsize=24)
plt.ylabel('用户人数', fontsize=24)
plt.title('用户购买周期分布图', fontsize=24)
  • 典型的(指数)长尾分布,大部分用户的消费间隔比较短。我们可以将时间召回点设为消费后立即赠送优惠券,消费后10天询问用户礼品怎么样,消费后20天提醒优惠券到期,消费后30天短信推送

用户生命周期分析

用户生命周期:指用户从第一次消费到最后一次消费的时间间隔

user_min = df.groupby('userid').datetime.min()  # 第一次消费时间
user_max = df.groupby('userid').datetime.max()  # 最后一次消费时间
user_lifecycle = user_max - user_min           # 用户生命周期
life_cycle = user_lifecycle.reset_index()      # reset_index()函数是将其转换成dataframe
life_cycle.describe()
  • 用户的平均生命周期为134天,比预想的周期还要高出许多,并且其中最长的生命周期是544天
  • 有一半以上的用户只消费了一次,但这不是我们想要的答案,故应将只消费了一次的新客排除,来计算所有消费过两次以上的老客的生命周期
# np.timedelta64(1, ‘D’),D表示天,1表示1天,作为单位使用的。因为max-min已经表示为天了,
# 两者相除就是周期

life_cycle['day'] = life_cycle.datetime / np.timedelta64(1, 'D')
life_cycle.query('day > 0')['day'].hist(bins=100)
  • 上图可见,用户生命周期呈现双峰趋势,20天内生命周期的用户是一个高峰,400至500天内生命周期的用户是另一个高峰
  • 根据此情况,应该在20天内对客户进行引导,促进其再次消费并形成消费习惯,延长其生命周期;在100至400天的用户,也要根据其特点推出有针对性的营销活动,引导其持续消费。

分析去掉只有首次消费的新客后,剩余的用户生命周期平均值

life_cycle.query('day > 0').mean()
userid                       11718.6
datetime    276 days 01:04:31.344216
day                          276.045
dtype: object
  • 可见,若在用户首次消费后,加强对其再次消费的引导,可将其生命周期延长至原来的两倍。

6.用户分层

根据用户价值分析——建立RFM模型

为了进行精细化运营,可以利用RMF模型对用户价值指数(衡量历史到当前用户贡献的收益)进行计算,其中

  • R:客户最近一次交易时间的间隔。R值越大,表示客户交易发生的日期越久,反之则交易发生的日期越近
  • F:客户在最近一段时间内消费频率。F值越大,表示客户交易越频繁,反之则表示客户交易不够活跃(数据中消费次数较为固定,故我们选择购买产品数量作F)
  • M:客户在最近一段时间内交消费金额。M值越大,表示客户价值越高,反之则表示客户价值越低

根据上述三个维度,对客户做细分



# 建立一个透视表
rfm = df.pivot_table(index='userid', values=['datetime', 'products', 'amounts'], 
                     aggfunc={'datetime': 'max', 'products': 'sum', 'amounts': 'sum'})
rfm.head()

修改表中的字段并且添加R字段

# R = 当前时间-消费时间,数据中为方便统计,使用源数据最大时间
rfm['R'] = (rfm['datetime'].max() - rfm['datetime'])/np.timedelta64(1,'D')
rfm.rename(columns={'amounts': 'M', 'products': 'F'}, inplace=True)
rfm.head()

构建RFM模型公式

  • 怎样可以让客户分组呢,什么样的客户是重要客户呐!!当然肯定是消费产品多,消费金额高,消费距今时间短的了。但是这些指标怎样能体现出来呢,这就要用到均值,如果这个值跟均值相减是负数说明消费水平不高,但是又分成几种情况。

  • 均值相减之后分成了这样几种情况 可以判断一下假设每个值正数就是“1”,负数就是“0”:

      '111':'重要价值客户',
      '011':'重要保持客户',
      '101':'重要挽留客户',
      '001':'重要发展客户',
      '110':'一般价值客户',
      '010':'一般保持客户',
      '100':'一般挽留客户',
      '000':'一般发展客户'
    
def 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

rfm['label'] = rfm[['R', 'F', 'M']].apply(lambda x: (x-x.mean())).apply(func, axis=1)[图片上传中...(1614686134(1).png-be6984-1614686143174-0)]

rfm.head()

使用数据透视表统计出各个层级的客户数量和消费总金额

rfm.pivot_table(index='label', values=['M', 'F'], aggfunc={'M': 'sum', 'F': 'count'})
  • 以上为不同层次用户的消费人数,一般挽留用户的消费人数排名第一,有14074人,重要保持客户排名第二,有4554人,与一般挽留用户差距比较大,但累计消费金额最多,业务方可以根据结果对客户分类运营,降低营销成本,提高ROI(投资回报率)

用户活跃度分层

  • 新用户的定义是第一次消费。
  • 活跃用户即老客,在某一个时间窗口内有过消费。
  • 不活跃用户则是时间窗口内没有消费过的老客。
  • 回流用户是在上一个窗口中没有消费,而在当前时间窗口内有过消费。
pivoted_counts = df.pivot_table(index='userid',columns='month',values='datetime',aggfunc='count').fillna(0) #每个用户每月的消费次数
#这边只看用户每个月有没有消费过,消费次数这边不考虑
df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0) #1代表本月消费,0代表未消费
def active_status(data): #data是df_purchase的一行
    status=[]
    for i in range(18): #一共有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 status
purchase_stats=df_purchase.apply(active_status,axis=1)#得到用户分层结果
purchase_stats_ct=purchase_stats.replace({'unreg':np.NaN}).apply(lambda x:pd.value_counts(x)) #用NaN替代unreg,以便后续计算不包含这些数据,未注册不考虑
purchase_stats_ct.fillna(0).T.plot.area()#为了便于画图,将缺失值补齐
df1 = purchase_stats_ct.fillna(0).T.apply(lambda x : x/x.sum(), axis=1) #求出每月各层用户占比
df1

由上表可知,每月的用户消费状态变化:

  • 新客用户:仅在前三个月,后续再无新增客户。
  • 活跃用户:比例持续下降,说明持续消费的用户数量在减少,也说明运营部门的促活效果并不好。
  • 回流用户:比例也稍有下降,在4%左右波动。
  • 不活跃用户:比例稍有上升,流失较大

有多少用户只消费了一次

a=df.groupby('userid').datetime.agg(['min','max']).reset_index()  
b=(a['min']==a['max']).value_counts()
plt.pie(x = b,
       autopct = '%.1f%%',
       shadow = True,
       explode = [0.08,0],
       textprops = {'fontsize' : 11})
plt.axis('equal') 
plt.legend(['仅消费一次','多次消费'])
  • 图中所示,一半以上的用户仅消费了一次,这也说明了运营不利,留存效果不好

复购率

复购率:自然月内,购买多次的用户在总消费人数中的占比(若客户在同一天时间内消费两单,也算复购)

user_df = df.pivot_table(index='userid', columns='month', values='datetime', aggfunc='count').fillna(0)
user_df.head() # 每个用户在每月的订单
def func(x):
    if x>1:
        return '1'
    elif x>0:
        return '0'
    else:
        return np.nan
user_df2 = user_df.applymap(func)  # 购买两次以上的客户为1,购买一次的客户为0,无购买记录为空
user_df2 = user_df2.astype('float64')  # def语句中修改了dataframe的数据类型,lambda代替def语句更佳
(user_df2.sum()/user_df2.count()).plot(figsize=(10,4))   # 计算复购率作图

说明:图上可以看出早期因为大量新用户加入的关系,新客的复购率并不高,如1月新客们的复购率只有6%左右。而这批用户只购买了一次,所以导致复购率偏低,4月以后,复购率比较稳定,在20%左右

回购率

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

df_purchase.head()  # 1代表本月消费,0代表未消费
col = ['1997-01-01', '1997-02-01', '1997-03-01', '1997-04-01',
               '1997-05-01', '1997-06-01', '1997-07-01', '1997-08-01',
               '1997-09-01', '1997-10-01', '1997-11-01', '1997-12-01',
               '1998-01-01', '1998-02-01', '1998-03-01', '1998-04-01',
               '1998-05-01', '1998-06-01']


def purchase_return(data):
    status=[]
    for i in range(17):
        if data[i]==1:
            if data[i+1]==1:
                status.append(1)
            if data[i+1]==0:
                status.append(0)
        else:
            status.append(np.nan)
    status.append(np.nan)  #定义最后一个月的数据
    return pd.Series(status,index=col)
pivoted_purchase_return = pivoted_purchase.apply(purchase_return,axis = 1)
(pivoted_purchase_return.sum()/pivoted_purchase_return.count()).plot(figsize=(10,4))
  • 上图可以看出,在初期用户的回购率并不高,1月的回购率只有15%左右,4月份起回购率稳定在30%左右。
  • 从每月有回购消费的用户数数据可以看出,回购用户数整体有下降趋势。
  • 对回购率的分析,再次说明了对于新用户,在其第一次消费后的三个月内是一段重要的时期,需要营销策略积极引导其再次消费及持续消费。
  • 另外,对于有持续消费的老客,也要适时推出反馈老客户的优惠活动,以加强老客的忠诚度。

大客户的贡献率

用户销售额贡献

user_money = df.groupby('userid')['amounts'].sum().sort_values().reset_index()
user_money['money_cumsum'] = user_money['amounts'].cumsum()  #逐行计算用户累计金额,最后一行是总消费金额
money_total=user_money['money_cumsum'].max()
user_money['prop'] = user_money.apply(lambda x:x.money_cumsum/money_total,axis=1)
user_money['prop'].plot()

前20000个用户,大约80%的用户贡献了40%的销售额,20%的用户贡献了60%的销售额

用户销售量贡献

根据用户销售金额贡献计算方式,同理可得:

user_productsSum=df.groupby('userid').products.sum().sort_values().reset_index()
user_productsSum['products_cumsum']=user_productsSum.products.cumsum()
productsSum_total=user_productsSum.products_cumsum.max()
user_productsSum['prop']=user_productsSum.apply(lambda x:x.products_cumsum/productsSum_total,axis=1)
user_productsSum.prop.plot()

前20000名用户贡献了40%的消费,而后3500名用户贡献了60%的消费。符合二八趋势。也就是说我们只要维护了这3500个用户就可以把业绩KPI完成60%,如果能把3500个用户运营的更好就可以占比70%—80%之间

  1. 整体趋势:按年的月份趋势销量和销售额在1-3月份相对极高,然后骤降,原因可能跟这段时间的大力促销或与商品的季度属性有关。
  2. 用户个体特征:每笔订单的金额和商品购买量都集中在区间的低段水平,都是小金额小批量进行购买,此类交易群体,可在丰富产品线和增加促销活动提高转换率和购买率。
  3. 大部分用户的消费总额和购买总量都集中刚在低段,长尾分布,这个跟用户需求有关,可以对商品进行多元文化价值的赋予,增强其社交价值属性,提高用户的价值需求。
  4. 用户的消费周期:有二次以上消费的用户,平均68天,所以在50天到60天期间,应该对这批用户进行刺激召回,细致点,比如10天回复满意度,30天发放优惠券,55天的时候提醒优惠券的使用。
  5. 用户的生命周期:有二次及以上消费的用户的平均生命周期是276天。用户的生命周期分别在20天内与400至500天间,应该在20天内对客户进行引导,促进其再次消费并形成消费习惯,延长其生命周期;在100至400天的用户,也要根据其特点推出有针对性的营销活动,引导其持续消费。
  6. 新客户的复购率约为6%,老客户的复购率在20%左右;新客户的回购率在15%左右,老客户的回购率在30%左右,需要营销策略积极引导其再次消费及持续消费。
  7. 用户质量:用户个体消费有一定规律性,大部分用户的消费集中在2000以下,用户消费反应了2/8法则,消费排名前20%的用户贡献了80%的消费额。所以说,狠抓高质量用户是万古不变的道理,这些高质量客户都是“会员”类型,需要专门为会员优化购物体验,比如专线接听、特殊优惠等等。
    参考转载:
    https://zhuanlan.zhihu.com/p/109767465
    https://blog.csdn.net/qq_40821402/article/details/96748623?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&dist_request_id=9be6ca49-53a2-4955-9921-d44699b810f6&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

你可能感兴趣的:(2021-03-02)