最近为了更好的看出用户访问APP的路径,我研究了桑吉图,网上虽然有很多文章,但是都只是片面的讲解,实战过程有很多坑需要避免,所以,我总结了画桑吉图的血泪经验,给大家分享。下面先看看桑吉图的效果吧:
通过上面的图,我们能很清楚的看到,大部分用户是主动访问某宝首页,然后在首页分别访问了聚划算以及使用了搜索功能,在聚划算之后又访问了直播、每日大牌,最后跳出了。是不是很清晰?
访问路径和数据都是虚拟的,为了做这个案例而已,大家后面可以使用自己公司的数据。
什么是桑吉图
桑基图(Sankey diagram),即桑基能量分流图,也叫桑基能量平衡图。它是一种特定类型的流程图,右图中延伸的分支的宽度对应数据流量的大小,通常应用于能源、材料成分、金融等数据的可视化分析。因1898年Matthew Henry Phineas Riall Sankey绘制的“蒸汽机的能源效率图”而闻名,此后便以其名字命名为“桑基图”
在互联分析的主要意义是,其可以很清楚的看清楚用户访问APP的路径,可视化用户访问和跳出的重要节点。
如何画桑吉图
画桑吉图主要有以下几步
第一步:数据源
我习惯是数据先处理成以下结构:
附上数据源代码用作练习:
# 导入包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pyecharts.charts import Sankey
from pyecharts import options as opts
import pyecharts
#数据源
df = pd.DataFrame({
'第一个页面': ['某宝首页', '某宝首页', '某宝首页', '某宝首页', '某宝首页', '某宝首页', '某宝首页', '某宝首页', '某宝首页', '某宝消息页', '某宝消息页', '某宝消息页'],
'第二个页面': ['搜索', '搜索', '搜索', '搜索', '聚划算', '聚划算', '聚划算', '聚划算', '聚划算', '交易物流', '交易物流', '活动优惠'],
'第三个页面': ['历史搜索', '历史搜索', '搜索发现', '搜索发现', '每日大牌', '每日大牌', '直播', '直播', '直播', '物流详情', '物流详情', '权益过期提醒'],
'第四个页面': ['搜索结果页', '跳出', '搜索结果页', '跳出', '物品详情页', '跳出', '观看直播', '跳出', '我的页面', '某旗舰店', '跳出', '跳出'],
'用户量-万': [77, 706, 56, 981, 871, 348, 638, 698, 912, 651, 627, 380]
})
第二步:定义节点
什么节点呢?其实就是所有用户访问页面的名称,用户从页面A到页面B,再到C。把所有页面都列出来。(可以看出使用了unique(),进行去重,这个地方需要注意,后面会说)
代码:
nodes = []
for i in range(0,4):
values = df.iloc[:,i].unique()
for value in values:
dic = {}
dic['name'] = value
nodes.append(dic)
结果:
第三步:定义边和流量
什么是定义边和流量呢?其实就是把A到B和B到C具体的转化量计算出来。
代码一:代码一的意义在于,用户访问路径是复杂的,可能有10步如果,我们需要看前四步流转情况的话,就要先聚合前四步。
first = df.groupby(['第一个页面','第二个页面'])['用户量-万'].sum().reset_index()
b = df.groupby(['第二个页面','第三个页面',])['用户量-万'].sum().reset_index()
c = df.groupby(['第三个页面','第四个页面',])['用户量-万'].sum().reset_index()
first.columns = ['source','target','value']
b.columns = ['source','target','value']
c.columns = ['source','target','value']
result = pd.concat([first,b,c])
result.head(10)
代码二:
如果就是看所有页面的话,直接使用这个代码就好。此时把result换成df就好了
linkes=[]
for i in result.values:
dic={}
dic['source']=i[0]
dic['target']=i[1]
dic['value']=i[2]
linkes.append(dic)
结果:
从这个结果就能看到每一步的流转,source是上一个页面,target是下一个页面,value是从上一个页面到下一个页面的用户量,比如红色框代表从消息页到交易物流页面的用户量是1278
第四步:画图
代码:
画图就直接使用下面代码就可以了,我们解释一下:
- init_opts=opts.InitOpts(width="1300px", height="500px"),控制整个画图的大小,如果页面比较多,那就需要比较大的画图区域,使用整个代码进行调参。
- label_opts=opts.LabelOpts(position='right'),是页面名称的显示位置,比如上面的1处聚划算,目前显示在右侧。
- node_gap=10,代表2处,聚划算和搜索之间的间距,页面少的时候,可以调大间距。
- node_width = 35,代表3处,是搜索柱子的粗细。
-
focus_node_adjacency ='allEdges'。是鼠标悬停上面显示高亮,可以看看开篇时候鼠标的效果。
pic=(
Sankey(init_opts=opts.InitOpts(width="1300px", height="500px"))
.add(
'',#图例名称
nodes,#传入节点数据
linkes,#传入边和流量数据
#设置透明度、弯曲度、颜色
linestyle_opt=opts.LineStyleOpts(opacity=0.3,curve=0.5,color='source'),
#标签显示位置
label_opts=opts.LabelOpts(position='right'),
#节点之间的距离
node_gap=10,
#orient="vertical",#查看垂直图片的操作
node_width = 35,
# 桑基图中节点的对齐方式,默认是双端对齐,可以设置为左对齐或右对齐,对应的值分别是:# left: 节点左对齐。# right: 节点右对齐。# justify: 节点双端对齐。
node_align = 'right',
# 距离右侧的距离
#pos_right = "10%",
# 距离左侧的距离
# pos_left = '1%',
#鼠标悬停时,节点高亮
focus_node_adjacency ='allEdges'
)
.set_global_opts(title_opts=opts.TitleOpts(title='用户行为'))
)
pic.render('app_act.html')
注意点
- 主要是需要注意一点是第二步定义节点时,使用的unique(),这个是去重所有的页面,但是有个场景就不能满足,并且是90%以上不满足:
- 比如用户在第一个页面访问之后就跳出了,那么为了保证数据结构,必须后面几个页面够赋值跳出。数据如下,此时你使用上面的代码是不能画出图。
数据源代码
- 比如用户在第一个页面访问之后就跳出了,那么为了保证数据结构,必须后面几个页面够赋值跳出。数据如下,此时你使用上面的代码是不能画出图。
df1 = pd.DataFrame({
'第一个页面': ['某宝首页', '某宝首页', '某宝消息页', '某宝消息页'],
'第二个页面': ['搜索', '跳出', '交易物流', '跳出'],
'第三个页面': ['历史搜索', '跳出', '物流详情', '跳出'],
'第四个页面': ['搜索结果页', '跳出', '跳出', '跳出'],
'用户量-万': [145, 313, 699, 520]
})
那么我们需要进行处理:
for i in range(0,4):
df.iloc[:,i] = df.iloc[:,i] + str(i)
结果:
然后就能使用后面的几步:定义节点--定义边和流量--画图。
#定义节点
nodes = []
for i in range(0,4):
values = df1.iloc[:,i].unique()
for value in values:
dic = {}
dic['name'] = value
nodes.append(dic)
#定义边和流量
first = df1.groupby(['第一个页面','第二个页面'])['用户量-万'].sum().reset_index()
b = df1.groupby(['第二个页面','第三个页面',])['用户量-万'].sum().reset_index()
c = df1.groupby(['第三个页面','第四个页面',])['用户量-万'].sum().reset_index()
first.columns = ['source','target','value']
b.columns = ['source','target','value']
c.columns = ['source','target','value']
result = pd.concat([first,b,c])
linkes=[]
for i in result.values:
dic={}
dic['source']=i[0]
dic['target']=i[1]
dic['value']=i[2]
linkes.append(dic)
#画图
pic=(
Sankey(init_opts=opts.InitOpts(width="1300px", height="500px"))
.add(
'',#图例名称
nodes,#传入节点数据
linkes,#传入边和流量数据
#设置透明度、弯曲度、颜色
linestyle_opt=opts.LineStyleOpts(opacity=0.3,curve=0.5,color='source'),
#标签显示位置
label_opts=opts.LabelOpts(position='right'),
#节点之间的距离
node_gap=10,
#orient="vertical",#查看垂直图片的操作
node_width = 35,
# 桑基图中节点的对齐方式,默认是双端对齐,可以设置为左对齐或右对齐,对应的值分别是:# left: 节点左对齐。# right: 节点右对齐。# justify: 节点双端对齐。
node_align = 'right',
# 距离右侧的距离
#pos_right = "10%",
# 距离左侧的距离
# pos_left = '1%',
#鼠标悬停时,节点高亮
focus_node_adjacency ='allEdges'
)
.set_global_opts(title_opts=opts.TitleOpts(title='用户行为'))
)
pic.render('app_act.html')
结果:
写在最后:
大家一定要使用上面的数据进行训练,体会其中的坑。。。
大家一定要使用上面的数据进行训练,体会其中的坑。。。
大家一定要使用上面的数据进行训练,体会其中的坑。。。