项目的背景及数据预处理过程,本文不再进行介绍。
可以参考上一篇博文:
电商用户行为分析案例–天池数据集User Behavior Data from Taobao
本文基于上文已经预处理并导入MySQL的数据,在Python环境下,连接数据库进行取数。
Python环境下,MySQL数据库的操作,可以参考博文:
Python环境下MySQL数据库的操作
分析的思路及角度,也可以参见上篇博文,本文不再赘述。
本文重点介绍两个方面:
1.Python环境下,连接MySQL并进行取数操作;
2.运用python强大的可视化库Pyecharts进行可视化分析,并制作简单的可视化仪表板。
在安装pyecharts库的时候,可能会遇到安装后报错的现象:
注意:直接pip安装,是安装的最新版本的pyecharts。而新版本需要在python 3.6+的环境下运行,建议各位安装新版本,老版本已经不维护,而且新旧版本并不兼容。
(本人的电脑安装的是python 3.5的环境,pyecharts安装好后,总是报错。所以又在虚拟机里装了个python 3.6的环境,使用就正常了。)
学习pyecharts,强烈推荐直接在官方文档学习,内容很丰富,各种接口参数也很容易找到。
pyecharts文档中文网址
import numpy as np
import pandas as pd
import pymysql #python环境下操作MySQL的库
from sqlalchemy import create_engine #python环境下基于ORM框架操作MySQL的库
import pyecharts.options as opts #pyecharts是一个比较强大的可视化库
from pyecharts.charts import Bar,Line,Funnel,Gauge,Page #本文会用到的几个表
from pyecharts.components import Table #表格展示会用到
from pyecharts.options import ComponentTitleOpts #表格里会用到
本文基于两种连接MySQL的方式都做尝试,其中sqlalchemy库取出的数据,可以直接读到Pandas里,易于处理。而比较简单一些的取数,比如就需要取一个数字,本文就用pymysql来处理。
#pymysql创建连接
conn=pymysql.connect(host='localhost',port=3306,user='root',passwd='***',db='test',charset='utf8')
#sqlalchemy创建连接
engine=create_engine('mysql+pymysql://root:passwd@localhost:3306/test?charset=utf8')
这些SQL语句上篇博文都有介绍,本文不再过多解释。
其中有个坑就是直接从上篇博文复制过来SQL语句的话,有些执行会报错。
原因是SQL语句中存在’%‘字符,这个跟Python默认字符是有冲突的。
解决方案就是:直接改为’%%'就不会报错了。
#总访问量
sql_pv='''
select count(behavetype) as 总访问量
from user
where behavetype = 'pv';
'''
#日均访问量
sql_day_pv='''
select dates,count(behavetype) as 日均访问量
from user
where behavetype = 'pv'
group by dates
order by dates;'''
#用户总数
sql_user_all='''
select count(distinct user_id) as 用户总数
from user;'''
#有购买行为的用户数量
sql_user_buy='''
select count(distinct user_id) as 购买用户数
from user
where behavetype = 'buy';'''
#用户的购物情况
#创建视图
user_view='''create view user_behave AS
select user_id,count(behavetype),
sum(case when behavetype = 'pv' THEN 1 ELSE 0 end) as 点击次数,
sum(case when behavetype = 'fav' THEN 1 ELSE 0 end) as 收藏次数,
sum(case when behavetype = 'cart' THEN 1 ELSE 0 end) as 加购数,
sum(case when behavetype = 'buy' THEN 1 ELSE 0 end) as 购买数
from user
group by user_id
order by count(behavetype) DESC;'''
#用户购物情况
sql_user_type='''select * from user_behave;'''
#复购率:产生两次或两次以上购买的用户占购买用户的比例
sql_user_buy2='''
select
sum(case WHEN 购买数 > 1 THEN 1 ELSE 0 end) as 购买数大于1次,
sum(case when 购买数 > 0 Then 1 ELSE 0 end) as 总购买数,
concat(round(sum(case WHEN 购买数 > 1 THEN 1 ELSE 0 end)/sum(case when 购买数 > 0 Then 1 ELSE 0 end)*100,2),'%%') as 复购率
from user_behave;'''
#用户行为转化漏斗
#用户购物行为统计
sql_user_buytype='''select
sum(点击次数) as 点击次数,
sum(收藏次数) as 收藏次数,
sum(加购数) as 加购数,
sum(购买数) as 购买数
from user_behave;'''
#用户购买行为转化率
sql_user_buytyperate='''SELECT
concat(round(sum(点击次数)/sum(点击次数)*100,2),'%%') as pv,
concat(round((sum(收藏次数)+sum(加购数))/sum(点击次数)*100,2),'%%') as pv_to_favCart,
concat(round(sum(购买数)/sum(点击次数)*100,2),'%%') as pv_to_buy
from user_behave;'''
#购买率高和购买率低的人群特点
sql_user_buy_rate_high1='''select user_id,点击次数,收藏次数,加购数,购买数,
round(购买数/点击次数*100,2) as 购买率
from user_behave
group by user_id
order by 购买率 DESC;'''
sql_user_buy_rate_high2='''select user_id,点击次数,收藏次数,加购数,购买数,
concat(round(购买数/点击次数*100,2),'%%') as 购买率
from user_behave
group by user_id
order by 购买数 DESC;'''
sql_user_buy_rate_low='''select user_id,点击次数,收藏次数,加购数,购买数,
concat(round(购买数/点击次数*100,2),'%%') as 购买率
from user_behave
group by user_id
order by 购买数;'''
#基于时间维度了解用户的行为习惯
#一天中用户的活跃时段分布
sql_user_hours='''select hours,count(behavetype) as 用户行为总量,
sum(case when behavetype = 'pv' THEN 1 ELSE 0 end) as 点击次数,
sum(case when behavetype = 'fav' THEN 1 ELSE 0 end) as 收藏次数,
sum(case when behavetype = 'cart' THEN 1 ELSE 0 end) as 加购数,
sum(case when behavetype = 'buy' THEN 1 ELSE 0 end) as 购买数
from user
group by hours
order by hours;'''
#一周中用户活跃时段分布
sql_user_weeks='''select date_format(dates,'%%W') as weeks,count(behavetype) as 用户行为总量,
sum(case when behavetype = 'pv' THEN 1 ELSE 0 end) as 点击次数,
sum(case when behavetype = 'fav' THEN 1 ELSE 0 end) as 收藏次数,
sum(case when behavetype = 'cart' THEN 1 ELSE 0 end) as 加购数,
sum(case when behavetype = 'buy' THEN 1 ELSE 0 end) as 购买数
from user
where dates between '2017-11-27' and '2017-12-03'
group by weeks
order by weeks;'''
#基于RFM模型找出有价值的用户
sql_rfm_set='''set @userBuyNum = (
select count(distinct user_id) as 购买用户数
from user
where behavetype = 'buy');'''
sql_rfm='''
select r.*,f.frequency,f.freq_rank,
(
(case when
r.recent_rank <= @userBuyNum*1/4 then 4
when (r.recent_rank > @userBuyNum*1/4) and (r.recent_rank <= @userBuyNum*2/4) then 3
when (r.recent_rank > @userBuyNum*2/4) and (r.recent_rank <= @userBuyNum*3/4) then 2
else 1 end)+
(case when
f.freq_rank <= @userBuyNum*1/4 then 4
when (f.freq_rank > @userBuyNum*1/4) and (f.freq_rank <= @userBuyNum*2/4) then 3
when (f.freq_rank > @userBuyNum*2/4) and (f.freq_rank <= @userBuyNum*3/4) then 2
else 1 end)
) as user_value
from
(select a.*,(@rank:=@rank+1) as recent_rank
FROM
(SELECT user_id,datediff('2017-12-04',max(dates)) as recent
from user
where behavetype = 'buy'
group by user_id
order by recent) as a,
(select @rank:=0) as b) as r
left JOIN
(select a.*,(@rank2:=@rank2+1) as freq_rank
FROM
(select user_id,count(behavetype) as frequency
from user
where behavetype = 'buy'
group by user_id
order by frequency DESC) as a,
(select @rank2:=0) as b) as f
on r.user_id = f.user_id;'''
使用完之后,必须关闭游标,并关闭连接。
#自动提交
conn.autocommit(True)
#创建游标
cursor=conn.cursor()
pandas有个接口read_sql_query或者read_sql,可以直接把取出的数读为pandas的数据格式。
#1.总访问量
cursor.execute(sql_pv)
for row in cursor:
pv=row
pv=pv[0]
#2.日均访问量
day_pv=pd.read_sql_query(sql_day_pv,engine)
#3.用户总数
cursor.execute(sql_user_all)
for row in cursor:
user_all=row
user_all=user_all[0]
#4.有购买行为的用户数量
cursor.execute(sql_user_buy)
for row in cursor:
user_buy=row[0]
#5.用户的购物情况
user_type=pd.read_sql_query(sql_user_type,engine)
#6.复购率
user_buy2=pd.read_sql_query(sql_user_buy2,engine)
#7.用户购物行为统计
user_buytype=pd.read_sql(sql_user_buytype,engine)
#8.用户购买行为转化率
user_buytyperate=pd.read_sql(sql_user_buytyperate,engine)
#9.1购买率高人群特征
user_buy_rate_high1=pd.read_sql(sql_user_buy_rate_high1,engine)
#9.2购买数高人群特征
user_buy_rate_high2=pd.read_sql(sql_user_buy_rate_high2,engine)
#9.3购买数低人群特征
user_buy_rate_low=pd.read_sql(sql_user_buy_rate_low,engine)
#10.一天中用户的活跃时段分布
user_hours=pd.read_sql(sql_user_hours,engine)
#11.一周中用户的活跃时段分布
user_weeks=pd.read_sql(sql_user_weeks,engine)
#12.RFM模型
#设定参数
cursor.execute(sql_rfm_set)
#提取RFM打分数据
rfm=pd.read_sql(sql_rfm,engine)
#关闭游标
cursor.close()
#关闭连接
conn.close()
至此,已取出所需要的所有数据:
#1.总访问量
#pv
#2.日均访问量
#day_pv
#3.用户总数
#user_all
#4.有购买行为的用户数量
#user_buy
#5.用户的购物情况
#user_type
#6.复购率
#user_buy2
#7.用户购物行为统计
#user_buytype
#8.用户购买行为转化率
#user_buytyperate
#9.1购买率高人群特征
#user_buy_rate_high1
#user_buy_rate_high2
#user_buy_rate_low
#10.一天中用户的活跃时段分布
#user_hours
#11.一周中用户的活跃时段分布
#user_weeks
#12.RFM模型
#rfm
#日均访问量
day_pv
#数据预处理为作图需要的数据格式
x_data=day_pv['dates'].apply(lambda x:str(x)).tolist()
y1_data=day_pv['日均访问量'].tolist()
y2_data=[]
for i in range(len(y1_data)):
if i ==0:
y2_data.append(None)
else:
rate=(y1_data[i]-y1_data[i-1])/y1_data[i-1]
y2_data.append('%.2f'%(rate*100))
#画图:直方图+折线图
bar = (
Bar(init_opts=opts.InitOpts(width="800px", height="400px")) #画布大小
.add_xaxis(xaxis_data=x_data) #添加X轴数据
.add_yaxis( #添加Y轴数据
series_name='访问量',
yaxis_data=y1_data,
label_opts=opts.LabelOpts(is_show=False), #不显示Y轴标签
)
.extend_axis( #添加副Y轴
yaxis=opts.AxisOpts(
name="增长率",
type_="value",
name_location='middle',
name_gap=40, #名称与坐标轴距离
min_=-10,
max_=30,
interval=10,
#axisline_opts=opts.AxisLineOpts(is_on_zero=False),
axislabel_opts=opts.LabelOpts(formatter="{value} %"), #坐标轴标签显示格式
)
)
.set_global_opts(
title_opts=opts.TitleOpts( #设置图标的标题
title='日均访问量'
),
tooltip_opts=opts.TooltipOpts( #提示框配置项
is_show=True, trigger="axis", axis_pointer_type="cross"
),
xaxis_opts=opts.AxisOpts( #X轴坐标轴配置项
type_="category",
axislabel_opts=opts.LabelOpts(rotate=45), #X坐标轴标签旋转45度
axisline_opts=opts.AxisLineOpts(is_on_zero=False), #坐标轴刻度线不在0刻度显示
axispointer_opts=opts.AxisPointerOpts(is_show=True, type_="shadow"),
),
yaxis_opts=opts.AxisOpts( #Y轴配置
name="访问量",
type_="value",
name_location='middle', #坐标轴名称显示的位置
name_gap=60, #坐标轴名称与轴线的距离
min_=300000,
max_=500000,
interval=50000,
axislabel_opts=opts.LabelOpts(formatter="{value}"), #标签显示格式
axistick_opts=opts.AxisTickOpts(is_show=True), #刻度线
splitline_opts=opts.SplitLineOpts(is_show=True), #分割线
),
)
)
line = (
Line()
.add_xaxis(xaxis_data=x_data)
.add_yaxis(
series_name="增长率",
yaxis_index=1, #Y轴为副Y轴
y_axis=y2_data,
label_opts=opts.LabelOpts(is_show=False),
)
)
bar.overlap(line).render_notebook()
#7.用户购物行为统计
#user_buytype
#8.用户购买行为转化率
#user_buytyperate
#数据预处理为作图需要的数据格式
buy_type=['点击次数','收藏+加购数','购买数']
buy_type_qty=[user_buytype.iloc[0,0],user_buytype.iloc[0,1:3].sum(),user_buytype.iloc[0,3]]
buytype=pd.DataFrame({'环节':buy_type,'次数':buy_type_qty})
#计算单一环节转化率
import numpy as np
temp1=np.array(buytype['次数'][1:])
temp2=np.array(buytype['次数'][0:-1])
single_convs=list(temp1/temp2)
single_convs.insert(0,1)
single_convs=[round(x,4) for x in single_convs]
buytype['单一环节转化率']=single_convs
#计算整体转化率
temp3=np.array(buytype['次数'])
temp4=np.ones(len(buytype['次数']))*buytype['次数'][0]
total_convs=(temp3/temp4).tolist()
total_convs=[round(x,4) for x in total_convs]
buytype['总体转化率']=total_convs
#漏斗图需要传入的数据格式
data=[[buytype['环节'].tolist()[i],round(buytype['总体转化率'].tolist()[i]*100,2)] for i in range(len(buytype))]
#画图:漏斗图
funnel=(
Funnel(init_opts=opts.InitOpts(width='800px',height='400px'))
.add(
series_name='',
data_pair=data,
gap=2,
tooltip_opts=opts.TooltipOpts(trigger='item',formatter='{b} : {c}%'), #提示框配置项
label_opts=opts.LabelOpts(is_show=True,position='inside'), #标签配置项
itemstyle_opts=opts.ItemStyleOpts(border_color='#fff',border_width=1), #图元样式配置项
)
.set_global_opts(title_opts=opts.TitleOpts(title='用户转化漏斗图')) #全局配置项:标题
)
funnel.render_notebook()
user_hours.head()
#数据预处理为作图需要的数据格式
x_data=user_hours['hours'].tolist()
y1_data=user_hours['点击次数'].tolist()
y2_data=user_hours['收藏次数'].tolist()
y3_data=user_hours['加购数'].tolist()
y4_data=user_hours['购买数'].tolist()
#画图:多重折线图。X轴下方会带有调节取值范围的滑块
line_day=(
Line(init_opts=opts.InitOpts(width="800px", height="400px"))
.add_xaxis(xaxis_data=x_data)
.add_yaxis(
series_name='点击次数',
y_axis=y1_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name='收藏次数',
y_axis=y2_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name='加购数',
y_axis=y3_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name='购买数',
y_axis=y4_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
title_opts=opts.TitleOpts(title="用户日活跃时段分布"),
tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross"), #提示框配置项
datazoom_opts=[ #X轴上可以滑动筛选
opts.DataZoomOpts(xaxis_index=0),
opts.DataZoomOpts(type_="inside"),
],
yaxis_opts=opts.AxisOpts(
type_="value",
axistick_opts=opts.AxisTickOpts(is_show=True),
splitline_opts=opts.SplitLineOpts(is_show=True),
),
xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
)
)
line_day.render_notebook()
user_weeks
#数据预处理为作图需要的数据格式
column_list={'Monday':1,'Tuesday':2,'Wednesday':3,'Thursday':4,'Friday':5,'Saturday':6,'Sunday':7}
user_weeks['weeks_num']=user_weeks['weeks'].map(column_list)
user_weeks.sort_values(by='weeks_num',inplace=True)
user_weeks.reset_index(drop=True,inplace=True)
x_data=user_weeks['weeks'].tolist()
y1_data=user_weeks['点击次数'].tolist()
y2_data=user_weeks['收藏次数'].tolist()
y3_data=user_weeks['加购数'].tolist()
y4_data=user_weeks['购买数'].tolist()
#画图:多重折线图
line_week=(
Line(init_opts=opts.InitOpts(width="800px", height="400px"))
.add_xaxis(xaxis_data=x_data)
.add_yaxis(
series_name='点击次数',
y_axis=y1_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name='收藏次数',
y_axis=y2_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name='加购数',
y_axis=y3_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.add_yaxis(
series_name='购买数',
y_axis=y4_data,
linestyle_opts=opts.LineStyleOpts( #线宽
width=1.5),
symbol_size=5, #标记大小
label_opts=opts.LabelOpts(is_show=False),
)
.set_global_opts(
title_opts=opts.TitleOpts(title="用户周活跃时段分布"),
tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross"), #提示框配置项
#datazoom_opts=[ #X轴上可以滑动筛选
# opts.DataZoomOpts(xaxis_index=0),
# opts.DataZoomOpts(type_="inside"),
#],
yaxis_opts=opts.AxisOpts(
type_="value",
axistick_opts=opts.AxisTickOpts(is_show=True),
splitline_opts=opts.SplitLineOpts(is_show=True),
),
xaxis_opts=opts.AxisOpts(type_="category", boundary_gap=False),
)
)
line_week.render_notebook()
user_buy2
gauge=(
Gauge(init_opts=opts.InitOpts(width="800px", height="400px"))
.add(series_name="业务指标", data_pair=[["复购率", 65.8]])
.set_global_opts(
legend_opts=opts.LegendOpts(is_show=False),
tooltip_opts=opts.TooltipOpts(is_show=True, formatter="{a}
{b} : {c}%"),
)
)
gauge.render_notebook()
table = Table()
headers = ["总访问量", "用户总数", "购买用户总数"]
rows = [
[pv,user_all,user_buy]
]
table.add(headers, rows)
table.set_global_opts(
title_opts=ComponentTitleOpts(title="总体指标")
)
table.render_notebook()
#一.日均访问量:bar
#二.用户转化漏斗图:funnel
#三.用户日活跃时段分布:line_day
#四.用户周活跃时段分布:line_week
#五.复购率:gauge
#六.总体指标:table
page = Page(layout=Page.DraggablePageLayout) #括号内的参数很重要,后面可以自由调整整个图的排版
page.add(table,gauge,bar,funnel,line_day,line_week) #按顺序拼接
page.render_notebook() #在jupyter notebook里查看
page.render('page1_user_taobao.html') #直接导出html格式文件
部分截图展示:
上面导出的结果是按顺序排版的html格式文件,然后我们可以直接在每个图像上进行缩放、拖拽,以调整成我们想要的排版。
排版调好后,点击左上角的Save Config,会生成一个chart_config.json格式的文件。
这个文件就是记录我们排版的一些参数,下一步要用到。
然后按下面几行代码执行后,就可以转换出排版后的html了:
Page.save_resize_html("page1_user_taobao.html",
cfg_file="chart_config.json",
dest="my_test.html")
下面是我简单做的一个排版,就是最终的可视化仪表盘了。
Pyecharts可视化功能非常强大,而且做出来的图表会呈现出动态的效果,展示效果既炫酷,又实用。博文中的截图无法有效展示,小伙伴们自己试一试吧~~