用户消费行为实战三

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_41479464/article/details/100069799

                                      用户消费行为实战三


                                                                  需求:


一、用户第一次消费(首购)


二、用户最后一次消费

三、新老客户消费比

  1. 多少用户仅消费一次?

  2. 每月新客户比?

四、用户分层

  1. #     RFM

  2. #     新、老、活跃、回流、流失

五、用户购买周期(按订单)

  1. #     用户消费周期描述

  2. #     用户消费周期分布

六、用户生命周期

  1. #     用户生命周期描述

  2. #     用户生命周期分布

#这份数据 分别是  用户的id  消费的日期 购买的产品数量,购买的金额

一、用户第一次消费(首购)

colums = ['usr_id','order_dt','order_products','order_amount']
#因为是txt的数据所以我用read_table
#这里的分割符是 多个空格
df = pd.read_table("CDNOW_master.txt",names=colums,sep='\s+')
#当我们看数据类型发现日期是 int类型,后期需要进行转换
print(df.info())
#转换日期的操作
df['order_dt'] = pd.to_datetime(df.order_dt,format="%Y%m%d")
#时间维度的转换 按照月份 ,values不能忘记加
df['month'] = df.order_dt.values.astype('datetime64[M]')
print(df.head())
#因为数据是按月的所以现在按照月份分组(聚合)
grouped_month = df.groupby('month')



#按照用户进行分组,然后对用户id进行求和描述
#用户首购距离日期最远第一次,先对所有用户聚合
grouped_user = df.groupby('usr_id')

#设置图像形状
plt.style.use('ggplot')
#然后求出最小的时间,也就是距离现在最遥远的时间
grouped_user.min().order_dt.value_counts().plot()

plt.savefig('用户首购距离最远.jpg')
plt.show()

结果: 

 

#分析:用户在第一次购买分布,集中在前三个月,其中,在2月11日至2月25日有一次剧烈的波动

二、用户最后一次消费

#用户首购距离日期最近第一次,也就是最后一次消费,先对所有用户聚合
grouped_user = df.groupby('usr_id')

#设置图像形状
plt.style.use('ggplot')
#然后求出最小的时间,也就是距离现在最遥远的时间
grouped_user.max().order_dt.value_counts().plot()
plt.savefig('用户首购距离最近.jpg')
plt.show()

可视化结果:

 

 #图像分析:用户最后一次购买的分布比在第一次分布广 # 大部分最后一次购买,集中在前三个月,说明有很多用户购买了一次后就不在进行购买 #随着时间的递增,最后一次购买数也在递增,消费呈现流失上升的状况

三、新老客户消费比:

多少用户仅消费一次?

# 新老客户消费比
user_life = grouped_user.order_dt.agg(['min','max'])
print(user_life.head())

结果:

01-第一次购买时间分布
# min()  时间最小,第一次购买
grouped_user.min().order_dt.value_counts().plot()
# 2月发生较大下跌  渠道发生变化,或者其他  可以做一些假设
 
  • 用户第一次购买分布,集中在前三个月,其中2月11日至2月25日有一次剧烈波动
02-最后一次购买时间分布
grouped_user.max().order_dt.value_counts().plot()

  • 用户最后一次购买的分布比第一次购买分布广
  • 大部分最后一次购买在前三个月,说明很多用户购买一次后就不再进行购买
  • 随着时间递增,最后一次购买数在递增,消费呈线性流失上升的情况

四、用户分层

上图结果分析:第一次消费也就是最小的日期是一月一号,最后一次消费也是一月一号。

print((user_life['min']==user_life['max']).value_counts())
#看看true和false谁更多

每月新客户比?

统计用户只消费一次和多余一次的比例:可以看见大部分是true,只消费一次

可视化代码:

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus'] = False
labels = ['只消费一次用户','多次消费用户']
plt.axis('equal') # 保证长宽相等
plt.pie(rate,explode=(0,0.15),labels=labels,autopct='%2.1f%%',startangle=90,colors=['r','orange'],radius=1.5)
plt.savefig("消费比")
#看看true和false谁更多

可视化结果:

RFM:

04-用户分层
#  RFM   消费额 次数  最近一次消费 进行透视
rfm = data.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)
print(rfm.head())

print(rfm[['R','F','M']].apply(lambda x:x-x.mean()).head())
#定义函数把其中的数字转换成对应的信息
# 负数是小于的   正式大于的
# R:离最近一次购买的天数   F:产品数(消费次数) M:消费金额   与均值的对比

数据解读: 负数是小于的   正式大于的   

R:离最近一次购买的天数   F:产品数(消费次数) M:消费金额   与均值的对比

#定义函数把其中的数字转换成对应的信息
# 负数是小于的   正式大于的
# R:离最近一次购买的天数   F:产品数(消费次数) M:消费金额   与均值的对比
def rfm_func(x):
    level = x.apply(lambda x:'1' if x>= 0 else '0')
    # 字符串拼接
    #  111,R>0,是距离平均消费时间要久,R越大 说明没有消费时间越久  ,F >0 M>0,消费次数和金额也是较高的,重要价值客户,依次类推
    label = level.R + level.F + level.M
    d = {
        '111':'重要价值客户',
        '011':'重要保持客户',
        '101':'重要挽留客户',
        '001':'重要发展客户',
        '110':'一般价值客户',
        '010':'一般保持客户',
        '100':'一般挽留客户',
        '000':'一般发展客户'
    }
    result = d[label]
    return result
# x - x.mean() (具体真实情况可以修改,不一定需要用均值)   切比雪夫也可以 > 200 极值人工处理掉
rfm['label'] = rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
print(rfm)

数据解读: 1  时间比较长,只消费了一次,消费金额低   一般挽留客户 
print(rfm.groupby('label').sum())

统计不通层次有哪些人数:

print(rfm.groupby('label').count())

从rfm分层可知,大部分用户为重要保持客户,但是这是由于极值的影响,所以rfm的划分标准应该以业务为准

     1、尽量用小部分的用户覆盖大部分的额度

     2、不要为了数据好看划分等级

我们想要看看层次用户占比人数:

# 各类类型用户占比
use_c = rfm.groupby('label').count()
plt.axis('equal')
labels = ['一般价值客户','一般保持客户','一般发展客户','一般挽留客户','重要价值客户','重要保持客户','重要发展客户','重要挽留客户']
plt.pie(use_c['M'],
       autopct='%3.1f%%',
       labels = labels,
       pctdistance=0.9,
       labeldistance = 1.2,
       radius=3,
       startangle = 15)

结果:

利用散点图来观察客户的不同层次:

# 对应标签,使用不同颜色表示
# 绿色为重要价值客户,红色为非重要价值用户
rfm.loc[rfm.label == '重要价值客户','color'] = 'g'
rfm.loc[~(rfm.label == '重要价值客户'),'color'] = 'r'
rfm.plot.scatter('F','R',c=rfm.color)

用户生命周期:

pivoted_counts = df.pivot_table(index = 'usr_id',
                                  columns = 'month',
                                  values = 'order_dt',
                                  aggfunc = 'count').fillna(0)
# pivoted_counts.head()
print(pivoted_counts.head())

五、用户购买周期(按订单)

  1. #     用户消费周期描述

  2. #     用户消费周期分布

#消费过的为1 ,没消费过的为0
data_purchase = pivoted_counts.applymap(lambda x: 1 if x > 0 else 0)
data_purchase.tail()
# 透视会补上  第一次从3月分开始购买 前面补成0 , 需要进行判,第一次消费作为生命周期的起始
# se.columns.values

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')

# 这里需要对返回的值进行转换,将列表转为Series
    return status
  • 若本月没有消费
    • 若之前是未注册,则依旧未注册
    • 若之前有消费,则为流失/不活跃
    • 其他情况,为未注册
  • 若本月有消费
    • 若是第一次消费,则为新用户
    • 如果之前有过消费,则上个月为不活跃,则为回流
    • 如果上个月为未注册,则为新用户
    • 除此之外,为活跃
purchase_stats = data_purchase.apply(active_status,axis=1,result_type ='expand')
# df.rename(columns={ df.columns[2]: "new name" }, inplace=True)
# purchase_stats.rename(columns={purchase_stats.columns:data_purchase.columns})
purchase_stats.head()

purchase_status_ct = purchase_stats.replace('unreg',np.NaN).apply(lambda x : pd.value_counts(x))
purchase_status_ct
# 未注册不希望参与处理  设置我空值

数据解读: 一月份有7846个用户   然后2月份分叉为不活跃用户 和 活跃用户    有8476个新用户 等等

 新用户转换为是否活跃等等 流失用户在增加

# 各个状态的占比 
purchase_status_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis=1)
purchase_status_ct.fillna(0).T.plot.area()

由上表可知,每月的用户消费转变

活跃用户,持续消费的用户,对应的是消费质量

回流用户,之前是不消费的本月才消费,采取唤回运营

不活跃用户,对应的是流失

用户购买周期 
data.order_dt.head(10)
# 把所有的数据进行一个错位  
data.order_dt.shift().head(10)

 

#   一个用户可能多个订单  每个订单的间隔 
order_diff = grouped_user.apply(lambda x:x.order_dt - x.order_dt.shift())
order_diff.head(10)

数据解读:ID为2     0天当天购买两次或以上,间隔为0     

     ID为3的用户          3-4间隔了87天   

NaT表示一个订单

 每个用户的平均订单是68天  中位值31天 最大值533天

# 去除单位  间隔天数分布图
(order_diff / np.timedelta64(1,'D')).hist(bins=20)

(user_life['max'] - user_life['min']).describe()
# 整体的生命周期

((user_life['max'] - user_life['min']) / np.timedelta64(1,'D')).hist(bins = 40)

  • 用户的生命周期受只购买一次的用户影响比较厉害 (可以进行排除 当特殊情况,想提取出购买一次以上的用户)
  • 用户均消费134天,中位数仅为0
u_l = ((user_life['max'] - user_life['min']).reset_index()[0] / np.timedelta64(1,'D'))
u_l[u_l > 0].hist(bins=40)

  • 左边比较高,还是有些用户的生命周期是比较短的,例如10、20天等
  • 有不少用户生命周期也是比较稳定

猜你喜欢

转载自blog.csdn.net/qq_41479464/article/details/100069799