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

Python项目实战

  • Python项目实战 —— 04. 淘宝用户行为分析
    • 一、背景
    • 二、解题思路
    • 三、数据分析
      • 3.1 数据清洗
      • 3.2 数据分析
        • 3.2.1 用户整体行为分析
        • 3.2.2 用户每日行为分析
        • 3.2.3 用户每时行为分析
        • 3.2.4 用户对商品品类的挑选分析
        • 3.2.5 漏斗分析
        • 3.2.6 用户分类(RFM分析)
    • 四、建议
    • 五、代码
      • 5.1 代码-用户整体行为
      • 5.2 代码-用户每日行为
      • 5.3 代码-用户每时行为
      • 5.4 代码-用户对商品品类的挑选
      • 5.5 代码-用户分类(RFM分析)

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)

3.2 数据分析

3.2.1 用户整体行为分析

Python项目实战 —— 04. 淘宝用户行为分析_第1张图片
   在此期间,用户的行为如下:访问次数是748w,访问人数是1w,人均访问次数是747.9次,数据详情如图所示…

3.2.2 用户每日行为分析

Python项目实战 —— 04. 淘宝用户行为分析_第2张图片
Python项目实战 —— 04. 淘宝用户行为分析_第3张图片
   自进入12月开始,访问次数和人数逐渐上升,且在双十二当天达到峰值,访问次数约43w次、人数约7.7k人,购买量1.4w件;此外,在双十二的前后一周内,每日的数据基本大于等于均值。
   付费率=付费人数/总人数,当日点击且购买的付费率均值是23.8%,当月点击且购买的付费率均值是77% (11月是72.4%,12月是81.8%)。

3.2.3 用户每时行为分析

Python项目实战 —— 04. 淘宝用户行为分析_第4张图片

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

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

Python项目实战 —— 04. 淘宝用户行为分析_第5张图片
   在点击量和购买量前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得分,并给客户分类;

Python项目实战 —— 04. 淘宝用户行为分析_第6张图片
Python项目实战 —— 04. 淘宝用户行为分析_第7张图片

  • 占比最多的是重要发展客户,这类客户消费频次低,我们需要提升他们的消费频率,可通过优惠券叠加等活动来刺激消费;
  • 其次是重要挽留客户,这类客户消费时间间隔较远,且消费频次低,需要主动联系客户(如短信、邮件、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')

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')
# 当日点击&购买的付费率
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))

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

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

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

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

你可能感兴趣的:(项目实战,python)