流量数据化运营应用场景
1. 流量采购
流量采购是指通过多种媒介和广告渠道采集或购买流量,从而实现流量目标。
在流量采购方面,数据主要支撑一下四个方面:
1.1 流量预测
对未来的预估的和推断,常被应用在业务执行前的计划和评估阶段。
如:在新浪首页投放一个banner,预计能带来多少访问量?
1.2 效果评估
对已经发生的过去做结果判断,以评估结果是否符合预期或是否存在异常情况。
如:昨日广告渠道A的跳出率增加了35%,正常吗?
1.3 效果分析
对广告数据进去探索和研究,以便发现进一步的数据观点和数据洞察。
如:为什么某大V的一篇转发文章能带来12万的访问量?
1.4 作弊检测
2.流量分发
流量分发是指如何对流量进行内部分配,通常这部分工作由网站运营中心完成。
运营中心通过以下4种方式进行流量分发。
2.1 内部广告
2.2 活动引导
2.3 自然引导
2.4 个性化推荐
流量数据化运营分析模型
1. 流量波动检测
2. 渠道特征聚类
3. 广告整合传播模型
4. 流量预测模型
案例——基于自动节点树的数据异常原因下探分析
part 1 导入库
import datetime
import numpy as np
import pandas as pd
from graphviz import Digraph
part 2 数据预处理
#读取数据
raw_data = pd.read_csv('advertising_data.csv')
#数据审查
print('{:*^60}'.format('Data overview:'),'\n',raw_data.tail(2))
print('{:*^60}'.format('Data dtpye:'),'\n',raw_data.dtypes)
***********************Data overview:***********************
date source site channel media visit
10691 2018/6/14 手机_精准营销 UC浏览器 活动 网址导航热词 -
10692 2018/6/14 精准营销 360浏览器 活动 新安装页面欢迎页 -
************************Data dtpye:*************************
date object
source object
site object
channel object
media object
visit object
dtype: object
#缺失值查询
na_cols = raw_data.isnull().any(axis=0)
print('{:*^60}'.format('NA Cols:'))
print(na_cols[na_cols]==True)
print('total NA lines is : {0}'.format(raw_data.isnull().any(axis=1).sum()))
**************************NA Cols:**************************
Series([], dtype: bool)
total NA lines is : 0
#替换字符'-'为0,然后转为数值型
raw_data['visit'] = raw_data['visit'].replace('-',0).astype(np.int64)
print('{:*^60}'.format('Data overview:'))
print(raw_data.tail(5))
***********************Data overview:***********************
date source site channel media visit
10688 2018/6/14 搜索 百度semtv 电视品牌词_PC 品牌词电视 1
10689 2018/6/14 CRM 准会员 手机 站内信 0
10690 2018/6/14 搜索 百度 百度商城品专 新闻品专 0
10691 2018/6/14 手机_精准营销 UC浏览器 活动 网址导航热词 0
10692 2018/6/14 精准营销 360浏览器 活动 新安装页面欢迎页 0
#字符串转日期
raw_data['date'] = pd.to_datetime(raw_data['date'],format='%Y/%m/%d')
print('{:*^60}'.format('Data dtypes:'))
print(raw_data.dtypes)
part 3 计算整体波动量
将每天的数据与其前一天的数据进行环比统计
环比变化率 = 变化值/昨日值
day_summary = raw_data.iloc[:,-1].groupby(raw_data.iloc[:,0]).sum()
day_change_value = day_summary.diff(1).rename('change')
day_change_rate = (day_change_value.shift(-1)/day_summary).round(3).rename('change_rate').shift(1)
day_summary_total = pd.concat((day_summary,day_change_value,day_change_rate),axis=1)
print('{:*^60}'.format('Data change summary:'))
print(day_summary_total.head())
part 4 指定日期自动下探分解
#定义变量
#分解对象
dimension_list = ['source','site','channel','media']
import datetime
#日期
the_day = pd.datetime(2018,6,7)
previos_day = the_day - datetime.timedelta(1)
#日期列名
day_col1 = datetime.datetime.strftime(the_day,'%Y-%m-%d')
day_col2 = datetime.datetime.strftime(previos_day,'%Y-%m-%d')
#数据对象
the_data = raw_data[raw_data['date'] == the_day].rename(columns={'visit':day_col1})
previos_data = raw_data[raw_data['date'] == previos_day].rename(columns={'visit':day_col2})
#数据合并
data_merge = the_data.iloc[:,1:].merge(previos_data.iloc[:,1:],on=dimension_list,how='outer')
data_merge = data_merge.fillna(0)
data_merge['change'] = data_merge[day_col1] - data_merge[day_col2]
data_merge.head()
visit,change,change_rate = day_summary_total[day_summary_total.index == the_day].values[0]
top_nodes = {'source':'all site','change':change,'change_rate':change_rate}
#自动节点分解
main_nodes = []
other_nodes = []
hidden_nodes = []
main_edges = []
other_edges = []
dim_copy = ['source','site','channel','media',day_col1,'change']
for ind,dimension in enumerate(dimension_list):
each_data = data_merge[dim_copy[ind:]]
each_merge = each_data.groupby([dimension],as_index=False)[day_col1,'change'].sum()
each_merge = each_merge.sort_values(['change'])
each_merge['each_change_rate'] = each_merge['change']/each_merge[day_col1]
each_merge = each_merge.drop(day_col1,axis = 1)
change_all = each_merge.sum().iloc[1]
if change_all<0 :
main_values = each_merge.iloc[0].tolist()
main_nodes.append(main_values)
other_nodes.append([f'{dimension}-others',change_all-main_values[1],1-main_values[2]])
hidden_nodes.append(each_merge.iloc[-1].tolist())
data_merge = each_data[each_data[dimension] == each_merge.iloc[0].iloc[0]]
else:
main_values = each_merge.iloc[-1].tolist()
main_nodes.append(main_values)
other_nodes.append([f'{dimension}-others',change_all-main_values[1],1-main_values[2]])
hidden_nodes.append(each_merge.iloc[0].tolist())
data_merge = each_data[each_data[dimension] == each_merge.iloc[-1].iloc[0]]
edge_values = main_values[1]/float(change_all)
main_edges.append(edge_values)
other_edges.append(1-edge_values)
part 5 画图展示
#定义样式
node_style = '<<table border="0"><tr><td width="20"><table border="1" cellspacing="0" VALIGN="MIDDLE"><tr><td bgcolor="{0}"><font color="{1}"><B>{2}</B></font></td></tr><tr><td>环比变化量:{3:d}</td></tr><tr><td>环比变化率:{4:.2%}</td></tr></table></td></tr></table>>'
edge_style = '<<table border="0"><tr><td><table border="0" cellspacing="0" VALIGN="MIDDLE" bgcolor="#ffffff"><tr><td>{0}</td></tr><tr><td>贡献率:{1:.0%}</td></tr></table></td></tr></table>>'
attr_node = {'fontname': "SimHei", 'shape': 'box','penwidth' : '0'} # 定义node节点样式
attr_edge = {'fontname': "SimHei"} # 定义edge节点样式
attr_graph = {'fontname': "SimHei", 'splines': 'ortho','nodesep' : '2'} # Graph的总体样式
#定义左侧父级图
parent_dot = Digraph(format='png', graph_attr = attr_graph, node_attr={'shape':'plaintext','fontname':'SimHei'})
features = ['全站', 'source','site', 'channel','media']
parent_edge = [(features[i],features[i+1]) for i in range(len(features)-1)]
parent_dot.edges(parent_edge)
#定义右侧子级图
child_dot = Digraph(node_attr=attr_node,edge_attr=attr_node)
for tree_depth in range(len(main_nodes)):
split_node_left = main_nodes[tree_depth]
split_node_right = other_nodes[tree_depth]
split_node_hidden = hidden_nodes[tree_depth]
if tree_depth == 0:
node_name = '汇总值'
node_top_label = node_style.format('black',"white",node_name,int(top_nodes['change']),top_nodes['change_rate'])
child_dot.node('汇总值',label=node_top_label)
else:
node_name = main_nodes[tree_depth-1][0]
node_label_left = node_style.format("#184da5","white",split_node_left[0],int(split_node_left[1]),split_node_left[2])
node_label_right = node_style.format("#d3d3d3","black",split_node_right[0],int(split_node_right[1]),split_node_right[2])
node_label_hidden = node_style.format("#72a518","black",split_node_hidden[0],int(split_node_hidden[1]),split_node_hidden[2])
edge_label_left = edge_style.format('主因子',main_edges[tree_depth])
edge_label_right = edge_style.format('其他因子',other_edges[tree_depth])
child_dot.node(split_node_left[0],label=node_label_left)
child_dot.node(split_node_right[0],label=node_label_right)
child_dot.node(split_node_hidden[0],label=node_label_hidden)
child_dot.edge(node_name,split_node_left[0],label=edge_label_left)
child_dot.edge(node_name,split_node_right[0],label=edge_label_right)
child_dot.edge(split_node_right[0],split_node_hidden[0],label='潜在因子')
parent_dot.subgraph(child_dot)
parent_dot.view('change_analysis_tree')
横向:
查询哪些特征对于上一层及的变化有主因子和其他因子贡献,这是贡献率的来源
纵向:
查询每个节点本身相对与前一天的环比变化率,这是本身随着时间的变化特征,能了解其自身波动水平