本数据集共有大约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分析;
查重 ➜ 缺失值处理 ➜ 数据加工(如时间字段的处理、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)
在此期间,用户的行为如下:访问次数是748w,访问人数是1w,人均访问次数是747.9次,数据详情如图所示…
自进入12月开始,访问次数和人数逐渐上升,且在双十二当天达到峰值,访问次数约43w次、人数约7.7k人,购买量1.4w件;此外,在双十二的前后一周内,每日的数据基本大于等于均值。
付费率=付费人数/总人数,当日点击且购买的付费率均值是23.8%,当月点击且购买的付费率均值是77% (11月是72.4%,12月是81.8%)。
在点击量和购买量前20的品类中,相同的品类共计有14种(已标星);
在点击量top20中,有7种商品的购买率低于均值;
在购买量top20中,有12种商品的购买率低于均值;
点击→收藏的转化率:3.22%
点击→加入购物车的转化率:4.46%
点击→支付的转化率:1.48%
建议:增加跨店满减、收藏加购送商品赠品、送福利等活动,引导用户收藏加购行为,从而提高用户购买转化率。
RFM分析步骤:①计算R/F/M值;②根据打分规则,分别计算Score_R/F/M;③根据平均值,分别计算Result_R/F/M(得分大于均值标记为2,反之为1);④计算RFM得分,并给客户分类;
综上,我的建议是:
① 在大促前,制定回报率高的活动(如淘宝的猫猫升级活动,可分为个人战和团队战,不同战队制定不同方案等);在大促后,给用户推荐购买量/点击量高且优惠的产品,达到刺激用户登陆app,从而提高访问量和访问次数的目的;
② 一天内用户最活跃的时间段是21-22点,可把握该黄金时段,集中进行营销活动提高用户购买转化率,如平台带货直播、分会场促销、限时抢购等。此外,可进行进一步分析,不同时间段进行不同推荐;
③ 关于热搜和热销商品,可加大优惠力度、精准匹配用户、针对点击量高而购买转化率低的商品可改善商品页、详情页以及评论区管理等,促使用户购买;
④ 针对不用客户实行不同运营策略,详见3.2.6 用户分类(RFM分析);
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')
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))
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')
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')
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,我们也会同步更新此文章。
谢谢大家🌹