• Python项目实战 —— 04. 淘宝用户行为分析


    Python项目实战–目录

    Python项目实战 —— 04. 淘宝用户行为分析

    一、背景

       本数据集共有大约1200万条数据,数据为淘宝APP2014年11月18日至2014年12月18日的用户行为数据,字段分别是:user_id用户身份(已脱敏)、item_id商品ID(已脱敏)、behavior_type用户行为类型(包含点击、收藏、加购物车、支付四种行为,分别用数字1、2、3、4表示)、user_geohash地理位置、item_category品类ID(商品所属的品类)、time用户行为发生的时间。

       点此下载数据集


    二、解题思路

       本文从以下几个角度,对淘宝用户进行行为分析:
    ① 不同维度用户行为数据;
    ② 用户感兴趣的商品品类;
    ③ 漏斗分析;
    ④ RFM分析;

    三、数据分析

    3.1 数据清洗

    查重 ➜ 缺失值处理 ➜ 数据加工(如时间字段的处理、astype等)

    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    
    df = pd.read_csv('/xxx/recommend_user.csv',parse_dates=['time'])
    df['date'] = df.time.dt.date
    df['hour'] = df.time.dt.hour
    
    print('文件中有{}行重复数据,已删除.'.format(len(df[df.duplicated()])))
    df.drop_duplicates(inplace=True,ignore_index=True)
    df.drop(['user_geohash','time'],axis=1,inplace=True)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    3.2 数据分析

    3.2.1 用户整体行为分析

    在这里插入图片描述
       在此期间,用户的行为如下:访问次数是748w,访问人数是1w,人均访问次数是747.9次,数据详情如图所示…

    3.2.2 用户每日行为分析

    在这里插入图片描述
    在这里插入图片描述
       自进入12月开始,访问次数和人数逐渐上升,且在双十二当天达到峰值,访问次数约43w次、人数约7.7k人,购买量1.4w件;此外,在双十二的前后一周内,每日的数据基本大于等于均值。
       付费率=付费人数/总人数,当日点击且购买的付费率均值是23.8%,当月点击且购买的付费率均值是77% (11月是72.4%,12月是81.8%)。

    3.2.3 用户每时行为分析

    在这里插入图片描述

    • 05-10点:人们逐渐醒来开始上班,利用路程时间访问app,访问人数和次数都在持续上升;
    • 10-17点:人们工作时间,利用空闲时间访问app,访问人数和次数都处于平稳状态;
    • 17-22点:人们下班有大量空余时间,可访问app购买自己所需商品,访问人数缓慢上升,但访问次数上升明显的,且在21&22点达到峰值;在此时间段购买量和人均购买次数都高于均值且上升明显;
    • 22-05点:因开始休息了,故访问人数和次数都在持续下降;

    3.2.4 用户对商品品类的挑选分析

    在这里插入图片描述
       在点击量和购买量前20的品类中,相同的品类共计有14种(已标星);
       在点击量top20中,有7种商品的购买率低于均值;
       在购买量top20中,有12种商品的购买率低于均值;

    3.2.5 漏斗分析

       点击→收藏的转化率:3.22%
       点击→加入购物车的转化率:4.46%
       点击→支付的转化率:1.48%
       建议:增加跨店满减、收藏加购送商品赠品、送福利等活动,引导用户收藏加购行为,从而提高用户购买转化率。

    3.2.6 用户分类(RFM分析)

       RFM分析步骤:①计算R/F/M值;②根据打分规则,分别计算Score_R/F/M;③根据平均值,分别计算Result_R/F/M(得分大于均值标记为2,反之为1);④计算RFM得分,并给客户分类;

    在这里插入图片描述
    在这里插入图片描述

    • 占比最多的是重要发展客户,这类客户消费频次低,我们需要提升他们的消费频率,可通过优惠券叠加等活动来刺激消费;
    • 其次是重要挽留客户,这类客户消费时间间隔较远,且消费频次低,需要主动联系客户(如短信、邮件、APP推送等),调查清楚哪里出现了问题;
    • 重要价值用户是优质客户,可以有针对性地给这类客户提供VIP服务,如淘宝VIP会员卡等等;
    • 重要保持客户,这类客户消费时间间隔较远,但是消费频次高,有可能就是需要买东西的时候,就高频购买,不需要就不再购物,对于这类客户,需要主动联系,了解客户的需求,及时满足这类用户的需求(提供优惠券促使消费);

    四、建议

       综上,我的建议是:
    ① 在大促前,制定回报率高的活动(如淘宝的猫猫升级活动,可分为个人战和团队战,不同战队制定不同方案等);在大促后,给用户推荐购买量/点击量高且优惠的产品,达到刺激用户登陆app,从而提高访问量和访问次数的目的;
    ② 一天内用户最活跃的时间段是21-22点,可把握该黄金时段,集中进行营销活动提高用户购买转化率,如平台带货直播、分会场促销、限时抢购等。此外,可进行进一步分析,不同时间段进行不同推荐;
    ③ 关于热搜和热销商品,可加大优惠力度、精准匹配用户、针对点击量高而购买转化率低的商品可改善商品页、详情页以及评论区管理等,促使用户购买;
    ④ 针对不用客户实行不同运营策略,详见3.2.6 用户分类(RFM分析);

    五、代码

    5.1 代码-用户整体行为

    s = '{}~{}期间,用户行为分析:'.format(df.date.min(),df.date.max())
    s1 = '访问次数\n{}'.format(df[df.behavior_type==1].user_id.count())
    s2 = '访问人数\n{}'.format(df[df.behavior_type==1].user_id.nunique())
    s3 = '购买量\n'+str(df[df.behavior_type==4].item_id.count())
    s4 = '购买人数\n{}'.format(df[df.behavior_type==4].user_id.nunique())
    s5 = '人均访问次数:{}'.format(round(df[df.behavior_type==1].user_id.count()/df[df.behavior_type==1]\
                                   .user_id.nunique(),1))
    s6 = '人均购买次数:'+str(round(df[df.behavior_type==4].item_id.count()/df[df.behavior_type==1].user_id.nunique(),1))
    s7 = '付费用户人均购买次数:'+str(round(df[df.behavior_type==4].item_id.count()/df[df.behavior_type==4]\
                                 .user_id.nunique(),1))
    s8 = '付费率:{}%'.format(round(df[df.behavior_type==4].user_id.nunique()/df.user_id.nunique()*100,2))
    
    plt.text(0,1,s,bbox=dict(facecolor='yellow',alpha=0.8),size=28)
    plt.text(0.1,0.7,s1,size=28)
    plt.text(0.6,0.7,s2,size=28)
    plt.text(1.1,0.7,s3,size=28)
    plt.text(1.6,0.7,s4,size=28)
    plt.text(0.1,0.4,s5,size=28)
    plt.text(1.1,0.4,s7,size=28)
    plt.text(0.1,0.1,s6,size=28)
    plt.text(1.1,0.1,s8,size=28)
    plt.axis('off')
    #plt.savefig('1.png',dpi=150,bbox_inches='tight')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    5.2 代码-用户每日行为

    d1_1 = df[df.behavior_type==1].groupby('date').agg({'user_id':['count','nunique']})
    d1_2 = df[df.behavior_type==4].groupby('date').agg({'user_id':['count','nunique']})
    d1 = pd.concat([d1_1,d1_2],axis=1)
    d1.columns = ['pv','uv','buy_count','buy_uv']
    d1['人均访问次数'] = round(d1.pv/d1.uv,2)
    d1['人均购买次数'] = round(d1.buy_count/d1.uv,2)
    d1['付费率'] = round(d1.buy_uv/d1.uv*100,2)
    
    plt.figure(figsize=(24,12))  # 全局标题用plt.suptitle 每个子图的标题用plt.title
    plt.suptitle('淘宝用户每日访问情况',fontsize=20,color='r',backgroundcolor='yellow')
    plt.subplot(2,2,1)
    plt.xticks(rotation=90)
    plt.plot(d1.index.astype(str),d1.pv,'.-',label='pv')
    plt.axhline(d1.pv.mean(),linestyle='--',label='pv均值')
    plt.text(0,d1.pv.mean(),str(round(d1.pv.mean(),1)),fontsize=16)
    plt.legend()
    plt.subplot(2,2,2)
    plt.xticks(rotation=90)
    plt.plot(d1.index.astype(str),d1.uv,'.-',label='uv')
    plt.axhline(d1.uv.mean(),linestyle='--',label='uv均值')
    plt.text(0,d1.uv.mean(),str(round(d1.uv.mean(),1)),fontsize=16)
    plt.plot(d1.index.astype(str),d1.buy_uv,'.-',label='buy_uv')
    plt.axhline(d1.buy_uv.mean(),color='orange',linestyle='--',label='buy_uv均值')
    plt.text(0,d1.buy_uv.mean(),str(round(d1.buy_uv.mean(),1)),fontsize=16)
    plt.legend()
    plt.subplot(2,2,3)
    plt.xticks(rotation=90)
    plt.plot(d1.index.astype(str),d1.人均访问次数,'.-',label='人均访问次数')
    plt.axhline(d1.人均访问次数.mean(),linestyle='--',label='人均访问次数均值')
    plt.text(0,d1.人均访问次数.mean(),str(round(d1.人均访问次数.mean(),1)),fontsize=16)
    plt.plot(d1.index.astype(str),d1.付费率,'.-',label='付费率')
    plt.axhline(d1.付费率.mean(),color='orange',linestyle='--',label='付费率均值')
    plt.text(0,d1.付费率.mean(),str(round(d1.付费率.mean(),1)),fontsize=16)
    plt.legend()
    plt.subplot(2,2,4)
    plt.xticks(rotation=90)
    plt.plot(d1.index.astype(str),d1.buy_count,'.-',label='buy_count')
    plt.axhline(d1.buy_count.mean(),linestyle='--',label='buy_count均值')
    plt.text(0,d1.buy_count.mean(),str(round(d1.buy_count.mean(),1)),fontsize=16)
    plt.legend(loc='upper left')
    plt.twinx()
    plt.plot(d1.index.astype(str),d1.人均购买次数,'.-',color='orange',label='人均购买次数')
    plt.axhline(d1.人均购买次数.mean(),color='orange',linestyle='--',label='人均购买次数均值')
    plt.text(0,d1.人均购买次数.mean(),str(round(d1.人均购买次数.mean(),1)),fontsize=16)
    plt.ylim([0,2])
    plt.legend()
    #plt.savefig('2.png',dpi=150,bbox_inches='tight')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    # 当日点击&购买的付费率
    df1 = df[df.behavior_type==1][['user_id','item_id','date']].drop_duplicates()
    df2 = df[df.behavior_type==4][['user_id','item_id','date']].drop_duplicates()
    df1['合并'] = df1.user_id.astype(str)+'&'+df1.item_id.astype(str)+'&'+df1.date.astype(str)
    df2['合并'] = df2.user_id.astype(str)+'&'+df2.item_id.astype(str)+'&'+df2.date.astype(str)
    df3 = pd.merge(df1,df2,how='left',on='合并')
    df4 = pd.concat([df1.groupby('date').agg({'user_id':'nunique'}),
               df3[df3.user_id_y.notna()].groupby('date_x').agg({'user_id_x':'nunique'})],axis=1)
    df4['rate'] = round(df4.user_id_x/df4.user_id*100,2)
    df4.columns = ['uv','buy_uv','rate']
    df4.plot(kind='line',secondary_y=['rate'],figsize=(16,4))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    5.3 代码-用户每时行为

    d2_1 = df[df.behavior_type==1].groupby('hour').agg({'user_id':['count','nunique']})
    d2_2 = df[df.behavior_type==4].groupby('hour').agg({'user_id':['count','nunique']})
    d2 = pd.concat([d2_1,d2_2],axis=1)
    d2.columns = ['pv','uv','buy_count','buy_uv']
    d2['人均访问次数'] = round(d2.pv/d2.uv,2)
    d2['人均购买次数'] = round(d2.buy_count/d2.uv,2)
    d2['付费率'] = round(d2.buy_uv/d2.uv*100,2)
    
    plt.figure(figsize=(24,12))  # 全局标题用plt.suptitle 每个子图的标题用plt.title
    plt.suptitle('淘宝用户每时访问情况',fontsize=20,color='r',backgroundcolor='yellow')
    plt.subplot(2,2,1)
    plt.plot(d2.index.astype(str),d2.pv,'.-',label='pv')
    plt.axhline(d2.pv.mean(),linestyle='--',label='pv均值')
    plt.text(0,d2.pv.mean(),str(round(d2.pv.mean(),1)),fontsize=16)
    plt.legend()
    plt.subplot(2,2,2)
    plt.plot(d2.index.astype(str),d2.uv,'.-',label='uv')
    plt.axhline(d2.uv.mean(),linestyle='--',label='uv均值')
    plt.text(0,d2.uv.mean(),str(round(d2.uv.mean(),1)),fontsize=16)
    plt.plot(d2.index.astype(str),d2.buy_uv,'.-',label='buy_uv')
    plt.axhline(d2.buy_uv.mean(),color='orange',linestyle='--',label='buy_uv均值')
    plt.text(0,d2.buy_uv.mean(),str(round(d2.buy_uv.mean(),1)),fontsize=16)
    plt.legend()
    plt.subplot(2,2,3)
    plt.plot(d2.index.astype(str),d2.人均访问次数,'.-',label='人均访问次数')
    plt.axhline(d2.人均访问次数.mean(),linestyle='--',label='人均访问次数均值')
    plt.text(0,d2.人均访问次数.mean(),str(round(d2.人均访问次数.mean(),1)),fontsize=16)
    plt.plot(d2.index.astype(str),d2.付费率,'.-',label='付费率')
    plt.axhline(d2.付费率.mean(),color='orange',linestyle='--',label='付费率均值')
    plt.text(0,d2.付费率.mean(),str(round(d2.付费率.mean(),1)),fontsize=16)
    plt.legend()
    plt.subplot(2,2,4)
    plt.plot(d2.index.astype(str),d2.buy_count,'.-',label='buy_count')
    plt.axhline(d2.buy_count.mean(),linestyle='--',label='buy_count均值')
    plt.text(0,d2.buy_count.mean(),str(round(d2.buy_count.mean(),1)),fontsize=16)
    plt.legend(loc='upper center')
    plt.twinx()
    plt.plot(d2.index.astype(str),d2.人均购买次数,'.-',color='orange',label='人均购买次数')
    plt.axhline(d2.人均购买次数.mean(),color='orange',linestyle='--',label='人均购买次数均值')
    plt.text(0,d2.人均购买次数.mean(),str(round(d2.人均购买次数.mean(),1)),fontsize=16)
    plt.legend()
    plt.ylim([0,1])
    #plt.savefig('3.png',dpi=150,bbox_inches='tight')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    5.4 代码-用户对商品品类的挑选

    d3_1 = df[df.behavior_type==1].groupby('item_category').user_id.count().rename('click')
    d3_2 = df[df.behavior_type==4].groupby('item_category').user_id.count().rename('buy')
    d3 = pd.merge(d3_1,d3_2,how='left',left_index=True,right_index=True).fillna(0)
    d3['rate'] = round(d3.buy/d3.click*100,2)
    m = d3.sort_values('click',ascending=False).head(20)
    n = d3.sort_values('buy',ascending=False).head(20)
    mn_i = list(set(m.index.astype(str))&set(n.index.astype(str)))
    mn_v = list(m.loc[eval(i),'click'] for i in mn_i)
    
    plt.figure(figsize=(16,10))
    plt.suptitle('商品品类Top20(标星的是在点击&购买中都出现的品类)',fontsize=20,color='r',backgroundcolor='yellow')
    plt.subplot(2,1,1)
    plt.title('点击量Top20的品类\n')
    plt.bar(m.index.astype(str),m.click,alpha=0.5,label='点击量')
    plt.bar(m.index.astype(str),m.buy,label='购买量')
    plt.scatter(mn_i,mn_v,c='r',marker='*',label='标星') #必须放后面,若放前面:前14个柱子都标星,出现错误
    plt.legend()
    plt.twinx()
    plt.plot(m.index.astype(str),m.rate,'g',label='购买率%')
    plt.axhline(m.rate.mean(),linestyle='--',label='购买率均值')
    plt.legend()
    plt.subplot(2,1,2)
    plt.title('\n购买量Top20的品类\n')
    plt.bar(n.index.astype(str),n.click,alpha=0.5)
    plt.bar(n.index.astype(str),n.buy)
    plt.scatter(mn_i,mn_v,c='r',marker='*')
    plt.twinx()
    plt.plot(n.index.astype(str),n.rate,'g',)
    plt.axhline(n.rate.mean(),linestyle='--')
    #plt.savefig('4.png',dpi=150,bbox_inches='tight')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    5.5 代码-用户分类(RFM分析)

    print('\033[5;30;43mRFM分析:\033[0m')
    print('\033[30;43m1.计算R/F/M值;\n2.根据打分规则,分别计算Score_R/F/M;\033[0m')
    print('\033[30;43m3.根据平均值,分别计算Result_R/F/M(得分大于均值标记为2,反之为1);\n4.计算RFM得分,并给客户分类;\033[0m')
    Score_dict = {222:'重要价值客户',122:'重要保持客户',212:'重要发展客户',112:'重要挽留客户',\
                  221:'一般价值客户',121:'一般保持客户',211:'一般发展客户',111:'一般挽留客户'}
    
    d5_1 = df[df.behavior_type==4].groupby('user_id').agg({'date':'max','item_id':'count'})
    d5_1.columns = ['buydate_max','F']
    d5_1['R'] = (pd.to_datetime('2014-12-31')-pd.to_datetime(d5_1.buydate_max)).dt.days
    
    d5 = d5_1[['R','F']].reset_index()
    #可根据 plt.hist(d5.R,bins=5)和实际意义,来确定labels(也可看看pd.cut/pd.qcut)
    d5['Score_R'] = pd.cut(d5.R,bins=15,labels=sorted(list(range(1,16)),reverse=True)).astype(float)
    d5['Score_F'] = pd.cut(d5.F,bins=15,labels=list(range(1,16))).astype(float)
    d5['Result_R'] = d5.Score_R.apply(lambda x:2 if x>d5.Score_R.mean() else 1)
    d5['Result_F'] = d5.Score_F.apply(lambda x:2 if x>d5.Score_F.mean() else 1)
    d5['Result_M'] = 2 #原数据没有金额,此处人工标记为2
    d5['Score_RFM'] = d5.Result_R*100+d5.Result_F*10+d5.Result_M
    d5['客户类型'] = d5.Score_RFM.map(lambda x:Score_dict[x])
    
    
    print('\033[5;30;43m\n按客户类型汇总:\033[0m')
    d6 = d5.groupby('客户类型').agg({'user_id':'count','R':'mean','F':'mean'}).round(2)
    d6.columns = ['人数','间隔天数','购买次数']
    d6
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    大家可以关注我的知乎或微信公众号的share16,我们也会同步更新此文章。
    谢谢大家🌹

  • 相关阅读:
    【Head First 设计模式】-- 策略模式
    数据治理:元数据管理篇
    求臻医学:重磅 共识发布
    3.获取元素
    Hudi第一章:编译安装
    【Python Odyssey】1-1 | Python初见面
    YOLOv7训练数据集
    借助ChatGPT使用Python搭建一个工具网站
    GO框架基础 (三)、xorm库
    Web服务器
  • 原文地址:https://blog.csdn.net/weixin_42330887/article/details/126234952