数据内容包括user_id(用户身份)、item_id(商品)、IDbehavior_type(用户行为类型,包含点击、收藏、加购物车、支付四种行为,分别用数字1、2、3、4表示)、user_geohash(地理位置)、item_category(品类ID,即商品所属的品类)、Time(用户行为发生的时间),其中user_id和item_id因为涉及隐私,做了脱敏处理,显示的是数字编号。
下面是具体的代码实现过程。
1. 导入相关工具和数据
# 导入相关库
import pandas as pd
import numpy as np
%matplotlib inline
import matplotlib.pyplot as plt
import seaborn as sns
dt = pd.read_csv('E:/tianchi_mobile_recommend_train_user.csv')
其中,seaborn库可实现对统计数据的可视化展示,是基于Matplotlib的Python数据可视化库。
2. 数据的处理
# 对其中的label进行重命名
dt=dt.rename(columns={'user_id':'用户名','item_id':'商品名','behavior_type':'用
户行为类型','user_geohash':'地理位置','InvoiceDate':'发票日期','item_category':
'品类名','CustomerID':'用户名','time':'行为时间'})
dt.apply(lambda x:sum(x.isnull())/len(x))# 计算缺失率(缺失数/总数)
# # 对时间数据进行处理,将日期与小时数据分开
dt['date']=dt['行为时间'].str[0:10]
dt['hour']=dt['行为时间'].str[11:]
dt['date']=pd.to_datetime(dt['date'])
dt['行为时间']=pd.to_datetime(dt['行为时间'])
dt['hour']=dt['hour'].astype(int)
dt.sample(5)
结果如图12-24所示。
# # 将数据集按时间列进行升序排列
dt.sort_values(by='行为时间',ascending=True,inplace=True)
# 舍弃原来的索引进行重置
dt.reset_index(drop=True,inplace=True)
# 查看处理后的数据信息
dt.info()
结果如图12-25所示。
dt.describe()
结果如图12-26所示。
3. 用户行为分析
在介绍用户行为分析前,先了解两个概念。
-
PV(Page View,访问量):具体是指网站的页面浏览量或者点击量,页面被刷新一次就计算一次;
-
UV(Unique Visitor,独立访客):访问网站的一台电脑客户端即一个访客。
1)日访问量分析:
# uv_daily记录每天不同的上线用户数量
uv_daily=dt.groupby('date')['用户名'].nunique().rename('uv')
uv_daily=uv_daily.reset_index().rename(columns={'用户名':'uv'})
uv_daily.set_index('date',inplace=True)
# pv_daily记录每天用户操作次数
pv_daily=dt.groupby('date')['用户名'].count()
pv_daily=pv_daily.reset_index().rename(columns={'用户名':'pv'})
pv_daily.set_index('date',inplace=True)
# UV同比
uv_daily['uv_lastday']=uv_daily.shift(1)
uv_daily['tb']=100*(uv_daily['uv']-uv_daily['uv_lastday'])/uv_daily['uv_
lastday']
formater="{0:.02f}".format
uv_daily['tb']=uv_daily['tb'].map(formater).astype('float')
-
nunique():该函数返回所有数据唯一值个数。unique()函数是以数组形式返回列的所有唯一值。
-
shift():该函数对数据进行移动的操作,默认值是1。注意这里移动的都是数据,而索引是不移动的,移动之后没有对应值的,就赋值为NaN。
-
formater="{0:.02f}".format相当于formater=lambda x: '%.02f',即x取小数点后两位。
# UV环比
uv_daily['uv_7days']=uv_daily['uv'].shift(7)
uv_daily['hb']=100*(uv_daily['uv']-uv_daily['uv_7days'])/uv_daily['uv_7days']
formater="{0:.02f}".format
uv_daily['hb']=uv_daily['hb'].map(formater).astype('float')
uv_daily.head(2)
结果如图12-27所示。
# PV同比
pv_daily['pv_lastday']=pv_daily.shift(1)
pv_daily['tb']=100*(pv_daily['pv']-pv_daily['pv_lastday'])/pv_daily['pv_
lastday']
formater="{0:.02f}".format
pv_daily['tb']=pv_daily['tb'].map(formater).astype('float')
# PV环比
pv_daily['pv_7days']=pv_daily.pv.shift(7)
pv_daily['hb']=100*(pv_daily['pv']-pv_daily['pv_7days'])/pv_daily['pv_7days']
formater="{0:.02f}".format
pv_daily['hb']=pv_daily['hb'].map(formater).astype('float')
pv_daily.head(2)
结果如图12-28所示。
同比,即同期比较,可以是本年度与上年度,也可以是上年同一个月份或季度与本年同期。同比发展速度一般是指本期发展水平与上年同期发展水平对比,而达到的相对发展速度。由此处求得的PV同比增长可以看出本期与之前同样的时间段内用户对该平台的点击变动情况,由UV的同比增长可以看出在同样时段中使用该平台的用户数量的变化。
环比,即连续两个单位周期(比如连续两月)内的量的变化比。如今年8月比今年7月。当然这里的单位不一定是月,它可以是任何时间单位,能反映本期比上期增长了多少。环比发展速度,一般是指报告期水平与前一时期水平之比,表明现象逐期的发展速度。由此处求得的PV环比增长可以看出连续时间段内用户对该平台的点击变动情况,由UV的环比增长可以看出使用该平台的用户数量的变化。
# 按照日期和用户行为进行分组
pv_detail=dt.groupby(['用户行为类型','date'])['用户名'].count()
pv_detail=pv_detail.reset_index().rename(columns={'用户名':'total_pv'})
# # 将时间格式转换,否则会调用最原始的数据形状,会包含时分秒的格式
pv_detail['date']=pv_detail['date'].dt.strftime('%Y-%m-%d')
pv_detail['用户行为类型']=pv_detail['用户行为类型'].map({1:'click',2:'collect',
3: 'add_to_cart',4:'payment'})
fig,axes=plt.subplots(2,1,sharex=True,figsize=(20,10)) # 可视化
sns.pointplot(x='date',y='total_pv',hue='用户行为类型',data=pv_detail,ax=axes[0])
sns.pointplot(x='date',y='total_pv',hue='用户行为类型',data=pv_detail[pv_detail
['用户行为类型']!='click'],ax=axes[1])
axes[0].set_title('pv different behavior type')
axes[1].set_title('pv different behavior type except click')
结果如图12-29所示。
从图12-29中可以看出,由于浏览点击的数量和其他用户行为不在一个数量级,故将其他三种类型单独列看,发现加购物车的人数高于其他两种类型。
pv_uv_daily=pd.concat([pv_daily,uv_daily],axis=1)
import matplotlib.dates as mdate
from matplotlib.dates import DateFormatter
pv_uv_daily['date']=pd.to_datetime(dt['date'])
plt.figure(figsize=(16,10))
plt.xlabel(' ',fontsize=9)
pv_uv_daily['pv'].plot(color='steelblue',label='每天访问量')
plt.ylabel('访问量')
plt.legend(loc=1)
fig=pv_uv_daily['uv'].plot(color='red',label='每天不同用户访问量',secondary_y=True)
plt.ylabel('访问用户量')
plt.xticks((pv_uv_daily.index),pd.date_range('2014-11-18','2014-12-18'))
plt.legend(loc=2)
plt.grid(True)
plt.gcf().autofmt_xdate()# 坐标轴时间刻度自动调整
fig.xaxis.set_major_formatter(DateFormatter('%Y-%m-%d'))
plt.rcParams['font.sans-serif']=['SimHei']
plt.show()
结果如图12-30所示。
由用户行为的日期折线图可以看出,用户行为也具有周期性特点,在11.21、11.28、12.5这三个周五都是一周内的最低值,12月10日至12月12日,用户点击量、收藏量、加购量都明显增长,在12月12日达到最大值,而购买量则在12月12日当日大幅度增加。
从图12-30中可以看出,每天用户会访问多次,用户访问量在双十二有明显激增,进而带来流量的激增。在此时段的用户消费情况应该远优于其他时段,此时一些小商家可以考虑在此段时间加入一些营销手段,提高自己的PV点击量,带动销量。
-
strftime():使用strftime()函数将时间格式化为我们想要的格式。
-
fig、axes:用来创建多维窗口,此处是一个2?的图。sharex:x轴一样,y轴不同;
-
figsize:图片的大小尺寸。
-
sns.pointplot():点图表示通过散点图点的位置对数值变量的中心趋势的估计。x, y, hue:数据字段变量名,根据实际数据,x、y常用来指定x、y轴的分类名称,hue常用来指定第二次分类的数据类别;ax:绘图时使用的Axes轴对象,ax=axes[0]是在第一个x轴上生成图像,依此类推。
-
concat():可以根据一个或多个键将不同DataFrame中的行连接起来,可以指定按某个轴进行连接,也可以指定连接的方式,axis=1实现横向连接。
-
matplotlib.dates:将datetime对象转换为浮点数,用于配置横坐标为日期格式。
-
DateFormatter:用于设定日期格式。
-
color='steelblue':颜色为亮钢兰色。
-
plt.legend(loc=1):此处表示图注的位置,而1、2、3、4分别对应图像的右上角、左上角、左下角、右下角,但两个图注不能重合。
-
plot(secondary_y=True):指右侧的y轴是否显示。
-
plt.rcParams['font.sans-serif']=['SimHei']:用来正常显示中文标签。
-
plt.grid(True):是否在图中显示网格。
2)小时访问量分析:
pv_hour=dt.groupby('hour').count()['用户名']
uv_hour=dt.groupby('hour')['用户名'].nunique().rename('uv')
pv_uv_hour=pd.concat([pv_hour,uv_hour],axis=1)
pv_uv_hour.columns=['pv','uv']
plt.figure(figsize=(16,10))
plt.xlabel(' ',fontsize=9)
pv_uv_hour['pv'].plot(color='steelblue',label='pv访问量')
plt.ylabel('访问量')
plt.legend(loc='upper right')
pv_uv_hour['uv'].plot(color='red',label='uv访问量',secondary_y=True)
plt.ylabel('访问用户量')
plt.xticks(range(0,24),pv_uv_hour.index)
plt.legend(loc='upper center')
plt.grid(True)
# 坐标轴时间刻度自动调整
plt.gcf().autofmt_xdate()
plt.show()
结果如图12-31所示。
由图12-31可知,pv和uv在凌晨0~5点期间波动情况相同,都呈下降趋势,访问量都比较小,同时在晚上18点后,pv访问量激增,但uv波动不大,很有可能是用户量趋于稳定但他们空闲时间增多,因此pv增多,所以晚上18~22点是该电商平台用户访问App的活跃时间段,可以在此段时间集中进行促销活动。
3)不同行为类型用户pv分析:
pv_detail=pd.pivot_table(columns='用户行为类型', index='hour', data=dt, values=
'用户名',aggfunc=np.size)
plt.figure(figsize=(16,9))
sns.lineplot(data=pv_detail.iloc[:,1:])
plt.show()
# 1-点击;2-收藏;3-购物车;4-支付
-
pivot_table():透视表,它是一种可以对数据动态排布并且分类汇总的表格格式。columns为列维度;index为行维度;values为对需要的计算数据进行筛选;aggfunc表示可以设置我们对数据聚合时进行的函数操作,即聚合依据,np.size用于统计矩阵元素个数。
-
Sns.lineplot():绘制折线图。
-
iloc[:,1:]:截取除第一列外的所有行列数据。
结果如图12-32所示。
由于点击的数量比其他操作数量多太多,故此处去掉查看其他具体操作的情况。
由图12-32可知点击相比较于其他三类用户行为,pv访问量较高,同时四种用户行为的波动情况基本一致,因此在晚上这一时间段,不管是哪种用户行为,pv访问量都是最高的。同时加入购物车这一用户行为的pv总量高于收藏的总量,购物车pv>收藏pv>支付pv,因此在后续漏斗流失分析中,要重点关注购物车这一用户类型。
4. 用户消费行为分析
1)购买用户的访问次数分析:
# 已经购买的用户里面访问次数
data_user_buy=dt[dt['用户行为类型']==4].groupby('用户名')['用户行为类型'].count()
# 查看用户的浏览次数
plt.hist(x=data_user_buy,bins=30)
plt.show()
-
plt.hist():直方图,其中x参数指定每个bin(箱子)分布的数据,对应x轴;bins参数指定bin(箱子)的个数,也就是总共有几幅条状图。
结果如图12-33所示。
用户消费次数普遍在13~17次,因此需要重点关注购买次数在20次以上的消费者用户群体。
2)日ARPPU。
ARPPU(Average Revenue Per Paying User,平均每用户付费额度)是指从每位付费用户身上获得的收入,它反映的是每个付费用户的平均付费额度。
ARPPU=总收入/活跃用户付费数量
因为本数据集中没有消费金额,因此在计算过程中用消费次数代替消费金额—人均消费次数=消费总次数/消费人数
# 针对已付费用户计算消费次数,即人均消费次数
data_use_buy1=dt[dt['用户行为类型']==4].groupby(['date','用户名'])
['用户行为类型'].count().reset_index().rename(columns={'用户行为类型':'total'})
data_use_buy1.describe()
结果如图12-34所示。
# 计算每天消费次数、消费人数,即每天人均消费次数
# 消费次数/消费人数
data_use_buy2=data_use_buy1.groupby('date').sum()['total']/data_use_buy1.
groupby('date').count()['total']
data_use_buy2.plot()
plt.show()
结果如图12-35所示。
data_use_buy2.describe()
从统计数据看,每天人均购买2次左右,最多购买近4次。
日ARPU(Average Revenue Per User,平均每用户收入)可通过(总收入/AU)计算得出,用于衡量产品的盈利能力和发展活力。
活跃用户数平均消费次数=消费总次数/活跃用户人数(每天有操作行为的用户)
dt['operation']=1
# 计算不同行为访问量
data_use_buy3=dt.groupby(['date','用户名','用户行为类型'])
['operation'].count().reset_index().rename(columns={'operation':'total'})
# 计算每天用户的平均消费次数
data_use_buy3.groupby('date').apply(lambda x:x[x.用户行为类型==4]
.total.sum()/len(x.用户名.unique())).plot()
plt.title('daily_ARPU')
结果如图12-37所示。
由图12-37可知,双十二这天的销量果然是最高的,附近日期的销量也远高于平常,盈利和点击量也是这段时间最可观的,双十二当天的平均每用户收入将近2(平常日ARPU可0.5左右)。
3)付费率,计算公式如下:
付费率=消费人数/活跃用户人数
具体实现代码如下:
data_use_buy3.groupby('date').apply(lambda x:x[x.用户行为类型==4]
.total.count()/len(x.用户名.unique())).plot()
plt.title('daily_afford_rate')
结果如图12-38所示。
用户付费率是衡量商家盈利情况的重要指标,从图12-38中可以看出,双十二的付费率在0.5,意味着浏览过商品的用户,有一半人都会选择购买商品,转化率已经很不错了(平常的付费率在0.23左右)。如果想要进一步提升用户的付费转化率,就需要梳理现有活动的转化流程,观察各转化环节的转化率。针对转化率较差的环节,思考转化较差的原因并采取相应措施,减少用户在各环节中的流失。例如:环节是否过多、流程是否过长,是否需要对环节进行合理的合并或删减;各环节的引导机制是否顺畅,文案/UI是否引导清晰,是否可以通过一些奖励来提高转化等。
4)同一时间段用户消费次数分布:
data_user_buy3=dt[dt.用户行为类型==4]
.groupby(['用户名','date','hour'])['operation'].sum().rename('buy_count')
sns.distplot(data_user_buy3)
print('大多数用户消费:{}次'.format(data_user_buy3.mode()[0]))
结果如图12-39所示。
-
sns.distplot():用来绘制直方图。
-
format():通过{}和:来代替传统%方式,即在%处依次填充入format的内容。
-
mode()[0]:mode()函数最后输出两个值,一个是众数值,另外是众数个数,[0]是返回众数值,整个语句的意思为返回data_user_buy3中的众数值。
5. 复购行为分析
复购情况,即两天以上有购买行为,一天内多次购买算一次。
复购率=有复购行为的用户数/有购买行为的用户总数
date_rebuy=dt[dt.用户行为类型==4].groupby('用户名')['date']
.apply(lambda x:len(x.unique())).rename('rebuy_count')
print('复购率:',round(date_rebuy[date_rebuy>=2].count()/date_rebuy.count(),4))
运行代码,得到复购率为0.8717。
round(number,digits)函数用于处理计算数据的四舍五入,number是数值,digits为保留几位小数,当digits<0时,在小数点左侧进行四舍五入。
# 所有复购时间间隔消费次数分布
data_day_buy=dt[dt.用户行为类型==4].groupby(['用户名','date']).operation.count().
reset_index()
data_user_buy4=data_day_buy.groupby('用户名').date.apply(lambda x:x.sort_values().
diff(1).dropna())
data_user_buy4=data_user_buy4.map(lambda x:x.days)
data_user_buy4.value_counts().plot(kind='bar')
plt.title('time_gap')
plt.xlabel('gap_day')
plt.ylabel('gap_count')
结果如图12-40所示。
-
sort_values():按照某一列的大小进行排序,默认为True,即升序排列。
-
diff():关于某列或者某行数据进行差分运算,axis=1,则进行列间的移动差分操作。
# 不同用户平均复购时间分析
sns.distplot(data_user_buy4.reset_index().groupby('用户名').date.mean())
结果如图12-41所示。
分析来看,多数用户复购率为0.04693,消费次数随着消费时间间隔的增加而不断下降,在1~10天之内复购次数比较多,10天之后用户很少进行复购,因此需要重视10天之内的用户复购行为,增加用户复购。不同用户平均复购时间呈正态分布,但是总体来看,呈现逐渐下降趋势。多数用户平均复购时间集中在1~5天时间间隔内。
6. 漏斗流失分析
漏斗流失分析是一套流程式数据分析,它能够科学反映用户行为状态以及从起点到终点各阶段用户转化率情况。
data_user_count=dt.groupby('用户行为类型').size()
data_user_count
# 查看点击数据
data_user_count[1]
# 计算总浏览量
pv_all=dt['用户名'].count()
pv_all
print('总浏览量—点击量 流失率: {:.2%}'.format((pv_all - data_user_count[1])/pv_all))
print('点击量-加入购物车量 流失率: {:.2%}'
.format((data_user_count[1] - data_user_count[3])/data_user_count[1]))
print('加入购物车量-收藏量 流失率: {:.2%}'
.format((data_user_count[3] - data_user_count[2])/data_user_count[3]))
print('收藏量—购买量 流失率: {:.2%}'
.format((data_user_count[2] - data_user_count[4])/data_user_count[2]))
结果如图12-42所示。
漏斗分析就是转化率分析,流量漏斗模型在产品中的经典运用是AARRR模型。衡量每一个节点的转换率,通过异常数据(即转换率过低处)找出异常节点,进而确定各个环节的流失率,分析用户怎么流失、为什么流失、在哪里流失。根据数据改进产品,最终提升整体转化率。从上面的分析中我们可以看出,从点击到加入购物车的转化率是最低的,流失率达到97%,所以要尽可能降低此处的流失率,比如可以改变商品的展示图片、提高留言区的评论质量等。
7. 用户价值RFM分析
from datetime import datetime
datenow=datetime(2014,12,20)
# 每位用户最近购买时间
recent_buy_time=dt[dt.用户行为类型==4].groupby('用户名')['date']
.apply(lambda x:datetime(2014,12,20)-x.sort_values().iloc[-1])
recent_buy_time=recent_buy_time.reset_index().rename(columns={'date':'recent'})
recent_buy_time.recent=recent_buy_time.recent.map(lambda x:x.days)
# 每个用户消费频率
buy_freq=dt[dt.用户行为类型==4].groupby('用户名').date.count()
.reset_index().rename(columns={'date':'freq'})
rfm=pd.merge(recent_buy_time,buy_freq,left_on='用户名',right_on='用户名',how=
'outer')
# 将各维度分成两个程度,基于等频分段,分数越高越好
rfm['recent_value']=pd.qcut(rfm.recent,2,labels=['2','1'])
rfm['freq_value']=pd.qcut(rfm.freq,2,labels=['1','2'])
rfm['rfm']=rfm['recent_value'].str.cat(rfm['freq_value'])
rfm.head()
结果如图12-43所示。
def trans_value(x):
if x == '22':
return '重要价值客户'
elif x == '21':
return '重要深耕客户'
elif x == '12':
return '重要唤回客户'
else:
return '流失客户'
rfm['用户等级']=rfm['rfm'].apply(trans_value)
rfm['用户等级'].value_counts()
结果如图12-44所示。
-
pd.qcut(x, q, labels=None)表示创建每个区间分割的数据个数相等。其中,x是相应的data,q则为组数,labels是标签名,而相应的pd.cut()则为创建差值相等(个数不同)的区间。
可以看出重要价值客户和流失客户是最多的,可以根据不同的客户类型制定相应的营销策略,一段时间后,再对比查看效果。
1)转化率分析(从点击到加入购物车):
# # 看下列标签
dt.columns
结果如图12-45所示。
# 不同用户行为类别的转化率
data_category=dt[dt.用户行为类型!=2].groupby(['品类名','用户行为类型']).operation.
count().unstack(1).rename(columns={1:'点击量',3:'加入购物车量',4:'购买量'}).
fillna(0)
# 转化率计算
data_category['转化率']=data_category['购买量']/data_category['点击量']
# 空值填充为0
data_category=data_category.fillna(0)
data_category=data_category[data_category['转化率']<=1]
data_category.describe()
结果如图12-46所示。
unstack(1)表示将列索引转成最内层的行索引,默认值就为1,将最内层的列索引转换为最内层的行索引。
由数据可得,转化率均值在1.5%左右,其中75%的用户转化率在1.9%左右,即点击但不购买的用户拉低了整体点击率,需收集用户浏览商品详情页的相关数据,分析出用户流失的原因,指导商家优化详情页,提高转化。
2)转化率分析(从加入购物车到购买):
data_category['感兴趣比率']=data_category['加入购物车量']/data_category['购买量']
data_category=data_category[data_category['感兴趣比率']<=1]
data_category.describe()
结果如图12-47所示。
# 查看购买量前10的商品的感兴趣比率情况
data_category.groupby('品类名').sum()['购买量'].sort_values(ascending=False)
data_category.head(10)
结果如图12-48所示。
data_category.groupby('品类名').sum()['购买量'].sort_values(ascending=False).head
(10).plot('bar')
结果如图12-49所示。
从数据可知,75%的用户将产品加入购物车后便会伺机购买,但整体均值在54%左右,即用户加入购物车到实际产生购买行为有近50%的流失比率。因本数据集中在双十二前夕,价格战成为主流,故推测价格是用户产生实际购买行为的主导因素,提醒商家在店铺页做好其他价值指引(售后服务,会员服务)等价值吸引,避免用户流失,同时保证备货充足。
9. 二八理论分析
data_category=data_category[data_category['购买量']>0]
value_8=data_category['购买量'].sum()*0.8
value_10=data_category['购买量'].sum()
data_category=data_category.sort_values(by='购买量',ascending=False)
data_category['累计购买量']=data_category['购买量'].cumsum()
data_category['分类']=data_category['累计购买量'].map(lambda x:'前80%' if x<=
value_8 else '后20%')
data_category.describe()
结果如图12-50所示。
data_category.groupby('分类')['分类'].count()/data_category['分类'].count()
结果如图12-51所示。
cumsum()用于求元素的累加和。根据分析结果可知,前80%销量有24.9%左右的商品品类承包,接近二八原则。同样也可以看出,有接近20%的销量由75.1%的商品品类提供。可以得出结论:用户对该平台消费已局限在某一品类。
根据以上的分析,相信你对消费者的行为已经有一定了解了,在后续的营销过程中,我们将针对已有产品,寻找所偏好的精准人群进行推广,同时根据客户的访问情况进行刺激,促进客户的消费行为,再考虑用户的消费数据,确定不同的客户群体的营销策略,最后实现精准营销啦!
本文摘编自《Python金融数据挖掘与分析实战》
声明:本文转自“华章计算机”公众号。
《新程序员003》正式上市,50余位技术专家共同创作,云原生和数字化的开发者们的一本技术精选图书。内容既有发展趋势及方法论结构,华为、阿字节跳动、网易、快手、微软、亚马逊、英特尔、西门子、施耐德等30多家知名公司云原生和数字化一手实战经验!