美文网首页
用户消费行为和消费趋势分析案例

用户消费行为和消费趋势分析案例

作者: 十一吖_cb39 | 来源:发表于2021-01-24 21:15 被阅读0次

    一、项目背景:

    这是一份单车网站用户消费行为的分析报告,通过对用户消费记录,深入分析用户消费行为,建立 RFM 模型,进行用户分层,发掘高价值用户并进行针对性管理和维护,实现用户运营精细化。

    二、分析思路:

    image.png

    三、分析工具:

    使用Python,PowerBI对数据进行了可视化分析

    四、分析目的:

    结合数据集,分析用户消费趋势和行为特征,了解业务和用户现状,进一步挖掘用户行为特征信息,为决策提供数据支持。

    五、分析过程:

    #导入数据
    import pandas as pd  
    import numpy as np 
    
    columns=['user_id','order_dt','order_products','order_amount']
    df=pd.read_table('bicycle_master.txt',names=columns, sep='\s+')
    
    • user_id:用户ID
    • order_dt:购买日期
    • border_products:购买产品数
    • order_amount:购买金额
    df.info()
    
    image.png
    df.head()
    
    image.png
    df.describe()
    
    image.png

    大部分订单只消费了少量商品(平均2.4),存在一定极值干扰
    用户的消费金额比较稳定,平均消费35元,中位数在25元,有一定极值的干扰

    df['order_dt']=pd.to_datetime(df.order_dt,format="%Y%m%d")
    df['month']=df.order_dt.values.astype('datetime64[M]')
    df['month']
    
    image.png

    对时间进行解析,一开始默认的格式是 int64的,默认会是 datetime64[ns] 类型,后面中括号表示 时间间隔是 ns
    下面是对 order_dt 列(取values),转换类型为datetime64[M],默认就会是每月的第一天了,同理设置为[Y]就是每年的1月1日,然后生成新的一列 month

    1.进行用户消费趋势的分析(按月)

    • 每月的消费总金额
    • 每月的消费次数
    • 每月的产品购买量
    • 每月的消费人数
    grouped_month=df.groupby('month')
    grouped_month_info = grouped_month[['order_amount','user_id','order_products']].agg({'order_amount':sum, 'user_id': 'count', 'order_products':sum})
    grouped_month_info
    
    image.png
    grouped_month_info.rename(columns = {'order_amount':'消费金额', 'user_id': '消费次数', 'order_products': '产品购买量'}, inplace=True)
    grouped_month_info.head()
    
    grouped_month_info['消费人次'] = grouped_month['user_id'].unique().map(len)
    #也可以用 grouped_month_info['消费人次'] = grouped_month['user_id'].unique().apply(lambda x:len(x))
    grouped_month_info.head()
    
    image.png
    #重置索引, 将month字段转换为字符型,
    grouped_month_info = grouped_month_info.reset_index()
    grouped_month_info['month'] = grouped_month_info['month'].astype(str)
    

    将处理过的数据,导入到Excel表格中

    grouped_month_info.to_excel(r'.\临时表\月销售额、销售次数、产品购买量、消费人数.xlsx')
    

    上面进行的汇总分析,其实可以用数据透视的方法更快实现,一次性求出结果

    df.pivot_table(index='month',
                  values=['order_products','order_amount','user_id'],
                  aggfunc={'order_products':'sum',
                          'order_amount':'sum',
                          'user_id':'count'}).head()
    

    将Excel数据导入到powerBI,可视化数据


    image.png

    由上图可知,消费金额在前三个月达到最高峰,后续消费较为稳定,有轻微下降趋势

    image.png

    由上图可知,产品购买量在前三个月达到最高峰,后续消费较为稳定,有轻微下降趋势


    image.png

    前三个月消费订单人数在10000笔左右,后续月份的平均消费人数则在2500人
    每月消费人数低于每月消费次数,但差异不大
    前三个月每月的消费人数在8000-10000之间,后续月份,平均消费人数在2000不到

    去重的方法有多种,这里也可以使用数据库思想,df.groupby(['month','user_id']).count().reset_index()

    2.用户个体消费分析

    • 用户消费金额,消费次数的描述统计
    • 用户消费金额和消费次数的散点图
    • 用户消费金额的分布图
    • 用户消费次数的分布图
    • 用户累计消费金额占比(百分之多少的用户占了百分之多少的消费额)
    grouped_user=df.groupby('user_id')
    grouped_user_info = grouped_user.sum()
    grouped_user_info.head()
    
    image.png
    #用户消费金额,消费次数的描述统计
    grouped_user.sum().describe()
    
    image.png

    用户平均购买了7张,但是中位值只有3,说明小部分用户购买了大量货物
    用户平均消费106元,中位值有43,判断同上,有极值干扰

    将处理过的数据,导入到Excel表格中

    grouped_user_info.to_excel(r'.\临时表\用户个体消费行为分析.xlsx')
    
    image.png
    • pd.cut() 利用进行切片分组
    grouped_user_sum_order_amount = grouped_user.order_amount.sum()
    grouped_user_sum_order_amount_lst = [i for i in range(0,int(grouped_user_sum_order_amount.max())+50,50)]
    grouped_user_sum_order_amount = pd.cut(grouped_user_sum_order_amount, bins=grouped_user_sum_order_amount_lst,labels = grouped_user_sum_order_amount_lst[1:])
    
    grouped_user_sum_order_amount
    
    image.png

    将处理过的数据,导入到Excel表格中

    grouped_user_sum_order_amount.to_excel(r'.\临时表\消费金额分布直方图.xlsx')
    

    从直方图可知,用户消费金额,绝大部分呈现集中趋势,小部分异常值干扰了判断,可以使用过滤操作排除异常
    使用切比雪夫定理过滤掉异常值,因为切比雪夫定理说明,95%的数据都分布在5个标准差之内,剩下5%的极值就不要了
    order_amount (mean = 106 ,std = 241) mean+5std = 1311


    image.png

    利用cumsum 求金额累加值

    user_cumsum=grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum()/x.sum())
    user_cumsum.tail(10)
    
    image.png

    将处理过的数据,导入到Excel表格中

    # 这里 reset_index() 是为了得到一个自然数的行标签,表示的就是人数,下面的图就可以看出来多少个少占多少百分比
    user_cumsum.reset_index().order_amount.to_excel(r'.\临时表\累积销售.xlsx')
    
    image.png

    按照用户消费金额进行升序排序,由图可以知道50%的用户仅贡献了11%的消费额度,而排名前5000的用户就贡献了60%的消费额度

    3.用户消费行为

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

    • 用户最后一次消费

    • 新老客户消费比

      • 多少用户仅消费一次
      • 每月新客占比
    • 用户分层

      • RFM模型
      • 新、老、活跃、回流、流失
    • 用户购买周期(按订单)

      • 用户消费周期描述
      • 用户消费周期分布
    • 用户生命周期(按第一次和最后一次消费) -用户生命周期描述

      • 用户生命周期分布
    • 用户第一次消费(首购)

    grouped_user_min = grouped_user.min().order_dt.value_counts().reset_index().rename(columns={'index':'first_date'})
    grouped_user_min['first_date'] =grouped_user_min['first_date'].astype(str)
    grouped_user_min.head()
    
    image.png

    将处理过的数据,导入到Excel表格中

    grouped_user_min.to_excel(r'.\临时表\用户首购.xlsx')
    
    image.png
    • 用户最后一次消费
    grouped_user_max = grouped_user.max().order_dt.value_counts().reset_index().rename(columns={'index':'last_date'})
    grouped_user_max['last_date'] =grouped_user_max['last_date'].astype(str)
    grouped_user_max.head()
    

    将处理过的数据,导入到Excel表格中

    grouped_user_max.to_excel(r'.\临时表\用户最后一次购买.xlsx')
    
    image.png
    • 新老客户消费比
    #新老客消费比
    # 统计只消费了一次的用户
    (user_life['min']==user_life['max']).value_counts()
    
    image.png

    有一半的用户,只消费了一次

    grouped_um = df.groupby(['month','user_id']).order_dt.agg(["min","max"])    
    grouped_um["new"] = (grouped_um["min"] == grouped_um["max"] )                # 新增列 True 为 新用户
    grouped_um.reset_index().groupby("month").new.value_counts()
    
    image.png
    • 用户分层
    rfm=df.pivot_table(index='user_id',
                      values=['order_products','order_amount','order_dt'],
                      aggfunc={'order_dt':'max',
                              'order_amount':'sum',
                              'order_products':'count'})
    rfm.head()
    

    得到最近一次消费,一般是计算 today 距离最近一次消费,这里因为时间太久远,就随便用的max值
    数值越大就越久远,分子得到的是一些天数类似 545 days(因为是时间格式相减),处以一个单位,就不会有单位了只留下数值
    重命名,也就是 R :消费时间 F:消费金额 M:消费频次

    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[['R','F','M']].apply(lambda x:x-x.mean())
    
    image.png

    用函数打标签

    def rfm_func(x):
        level=x.apply(lambda x:'1' if x>=0 else '0')
        # level 的类型是 series,index 是 R、F、M
    #     print(type(level))
    #     print(level.index)
        label=level.R + level.F + level.M
        d={
            # R 为1 表示比均值大,离最早时间近,F为1 表示 消费金额比较多,M 为1 表示消费频次比较多,所以是重要价值客户
            '111':'重要价值客户',
            '011':'重要保持客户',
            '101':'重要发展客户',
            '001':'重要挽留客户',
            '110':'一般价值客户',
            '010':'一般保持客户',
            '100':'一般发展客户',
            '000':'一般挽留客户',
        }
        result=d[label]
        return result
    
    # 注意这里是要一行行的传递进来,所以 axis=1,传递一行得到一个 111,然后匹配返回一个值
    rfm['label']=rfm[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
    
    rfm.loc[rfm.label=='重要价值客户','color']='重要价值客户'
    rfm.loc[~(rfm.label=='重要价值客户'),'color']='非重要价值客户'
    rfm.head()
    
    image.png

    将处理过的数据,导入到Excel表格中

    rfm.to_excel(r'.\临时表\RFM模型.xlsx')
    
    image.png
    rfm.groupby('label').sum()
    
    image.png
    rfm.groupby('label').sum()
    
    image.png

    从RFM 分层可知,大部分用户是重要保持客户,但是这是由于极值的影响,所以 RFM 的划分标准应该以业务为准,也可以通过切比雪夫去除极值后求均值,并且 RFM 的各个划分标准可以都不一样

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

    • 用户生命周期
      新客,活跃,回流,流失(一段时间不消费,或者不活跃)
    # 数据透视, userid为索引,月为列,求每月的消费次数,这里填充了
    pivoted_counts=df.pivot_table(index='user_id',
                                 columns='month',
                                 values='order_dt',
                                 aggfunc='count').fillna(0)
    pivoted_counts.head()
    
    image.png
    # 转变一下消费,有消费为1,没有消费为0
    df_purchase=pivoted_counts.applymap(lambda x:1 if x>0 else 0)
    df_purchase.tail()
    
    image.png
    # 这里由于进行数据透视,填充了一些 null 值为0,而实际可能用户在当月根本就没有注册,
    #这样会误导第一次消费数据的统计,所以写一个函数来处理
    def active_status(data):
        status=[]
        # 数据一共有18个月份,每次输入一行数据,这样进行逐月判断
        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 status             
    

    若本月没有消费,这里只是和上个月判断是否注册,有缺陷,可以判断是否存在就可以了
    若之前是未注册,则依旧为未注册
    若之前有消费,则为流失/不活跃
    其他情况,为未注册

    若本月有消费
    若是第一次消费,则为新用户
    如果之前有过消费,则上个月为不活跃,则为回流
    如果上个月为未注册,则为新用户
    初次之外,为活跃

    return:回流
    new:新客
    unreg:未注册
    active:活跃

    purchase_stats=df_purchase.apply(lambda x: pd.Series(active_status(x),index=df_purchase.columns),axis=1)
    purchase_stats.head()
    
    image.png
    # 这里把未注册的替换为空值,这样 count 计算时不会计算到
    # 得到每个月的用户分布
    purchase_stats_ct=purchase_stats.replace('unreg',np.NaN).apply(lambda x: x.value_counts())
    purchase_stats_ct
    
    image.png
    returnratee=purchase_stats_ct.apply(lambda x:x/x.sum(),axis=0)
    returnratee
    
    image.png
    purchase_stats_ct_info = purchase_stats_ct.fillna(0).T
    purchase_stats_ct_info
    
    image.png

    将处理过的数据,导入到Excel表格中

    purchase_stats_ct_info.index = purchase_stats_ct_info.index.astype(str)
    purchase_stats_ct_info.to_excel(r'.\临时表\用户分层-新、活跃、流失、回流.xlsx')
    
    image.png
    purchase_stats_ct_T = purchase_stats_ct.fillna(0).T.apply(lambda x:x/x.sum(),axis=1)
    purchase_stats_ct_T
    
    image.png
    • 用户购买周期(按订单)
    order_diff=grouped_user.apply(lambda x:x.order_dt-x.order_dt.shift())
    order_diff.head(10)
    
    image.png
    order_diff_info = (order_diff/np.timedelta64(1,'D'))
    order_diff_cut_lst = [i for i in range(0,int(order_diff_info.max())+1,10)]
    order_diff_info_hist = pd.cut(order_diff_info,bins=order_diff_cut_lst,labels=order_diff_cut_lst[1:])
    order_diff_info_hist
    
    image.png
    order_diff_info_hist = order_diff_info_hist.fillna(10)
    order_diff_info_hist.to_excel(r'.\临时表\用户购买周期时间差频率直方图.xlsx')
    
    image.png

    订单周期呈指数分布
    用户的平均购买周期是68天
    绝大部分用户的购买周期都低于100天

    • 用户生命周期(按第一次和最后一次消费)
    user_life.head()
    
    image.png
    # 用户生命周期(按第一次和最后一次消费)
    (user_life['max']-user_life['min']).describe()
    
    image.png
    user_life_info = ((user_life['max']-user_life['min'])/np.timedelta64(1,"D"))
    user_life_lst = [i for i in range(0,int(user_life_info.max())+1,10)]
    user_life_info_hist = pd.cut(user_life_info,bins=user_life_lst,labels=user_life_lst[1:])
    user_life_info_hist
    
    image.png
    user_life_info_hist_2 = user_life_info_hist.fillna(10)
    user_life_info_hist_2.to_excel(r'.\临时表\用户生命周期频率直方图.xlsx')
    
    image.png

    用户的生命周期受只购买一次的用户影响比较厉害(可以排除)
    用户均消费134天,中位数仅0天

    user_life["差值"]=(user_life["max"] - user_life["min"])/np.timedelta64(1,"D")
    user_life.head(5)
    
    image.png
    user_life_info_hist
    
    image.png
    user_life_info_hist.to_excel(r'.\临时表\用户生命周期频率直方图(忽略一次购买).xlsx')
    
    image.png

    4.复购率和回购率分析

    • 复购率
      • 自然月内,购买多次的用户占比(即,购买了两次以上)
    • 回购率
      • 曾经购买过的用户在某一时期的再次购买的占比(可能是在三个月内)
    purchase_r=pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
    
    # 区分一个,和一个以上的情况,以便于计算复购率,大于1为1,等于0 为0,等于1为0
    purchase_r=pivoted_counts.applymap(lambda x: 1 if x>1 else np.NaN if x==0 else 0)
    purchase_r.head()
    
    image.png
    purchase_r_reshop = (purchase_r.sum()/purchase_r.count()).reset_index(name = 'reshop')
    purchase_r_reshop
    
    image.png
    purchase_r_reshop['month'] = purchase_r_reshop['month'].astype(str)
    purchase_r_reshop.to_excel(r'.\临时表\复购人数与总消费人数比例.xlsx')
    
    image.png

    复购率稳定在20%所有,前一个月因为有大量新用户涌入,而这批用户只购买了一次,所以导致复购率降低

    • 回购率,知道是否消费就可以了
    df_purchase.head()
    
    image.png
    # 需要使用函数来判断是否回购:当月消费过的用户下个月也消费了叫做回购,这个定义可以改变
    def purchase_back(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)
        # 第18个月补充NaN
        status.append(np.NaN)
        return status
    
    indexs = df_purchase.columns
    indexs=df['month'].sort_values().astype('str').unique()
    purchase_b = df_purchase.apply(lambda x :pd.Series(purchase_back(x),index = indexs),axis =1)
    purchase_b.head()
    
    purchase_b_backshop = purchase_b.sum()/purchase_b.count()
    purchase_b_backshop.index = purchase_b_backshop.index.astype(str)
    purchase_b_backshop.to_excel(r'.\临时表\回购率.xlsx')
    
    image.png

    相关文章

      网友评论

          本文标题:用户消费行为和消费趋势分析案例

          本文链接:https://www.haomeiwen.com/subject/dwmmzktx.html