用户行为分析模型实践—— 漏斗分析模型
Posted vivo互联网
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用户行为分析模型实践—— 漏斗分析模型相关的知识,希望对你有一定的参考价值。
作者:vivo 互联网大数据团队- Wu Yonggang
在《用户行为分析模型实践(一)—— 路径分析模型》中,讲述了基于平台化查询中查询时间短、需要可视化的要求,并结合现有的存储计算资源以及具体需求,我们在实现中将路径数据进行枚举后分为两次进行合并。
本次带来的是系列文章的第2篇,本文详细介绍漏斗模型的概念及基本原理,并阐述了其在平台内部的具体实现。针对实际使用过程的问题,探索基于 ClickHouse漏斗模型实践方案。
一、背景需求
漏斗分析是衡量转化效果、进行转化分析的重要工具,是一种常见的流程式的数据分析方法。它能够帮助你清晰地了解转化情况,从多角度剖析对比,定位流失原因,提升转化表现。他主要立足于三大需求场景:
1. 定位用户流失具体原因。
2. 检测某个专题活动效果。
3. 针对不同版本,转化率情况对比。
二、概述
2.1 概念介绍
漏斗模型主要用于分析一个多步骤过程中每一步的转化与流失情况。其中有几个概念要了解:
其中漏斗模型分为两种:无序漏斗和有序漏斗。
定义如下:
无序漏斗:在漏斗的周期内,不限定漏斗多个步骤之间事件发生的顺序。
【计算规则】:假设一个漏斗中包含了 A、B、C 3个步骤,A步骤发生的时间可以在B步骤之前,也可以在B的后面。用户的行为顺序为A、B、C的组合都算成功的漏斗转化。即使漏斗步骤之间穿插一些其他事件步骤,依然视作该用户完成一次成功的漏斗转化。
有序漏斗:在漏斗的周期内,严格限定漏斗每个步骤之间的发生顺序。
【计算规则】:假设一个漏斗中包含了 A、B、C 3个步骤,A步骤发生的时间必须在B步骤之前,用户的行为顺序必须为A->B->C 。
和无序漏斗一样,漏斗步骤之间穿插一些其他事件步骤,依然视作该用户完成一次成功的漏斗转化。
三、 用漏斗进行的数据分析
了解了上面的关于漏斗模型的基本概念,我们看一下如何创建一个漏斗。
3.1 选一个漏斗类型
漏斗模型的类型一般分为有序漏斗和无序漏斗,它们的概念已在2.1做了详细的介绍。我们这里以无序漏斗为例,创建漏斗模型。
3.2 添加漏斗步骤
漏斗步骤就是漏斗分析的核心部分,步骤间统计数据的对比,就是我们分析步骤间数据的转化和流失的关键指标。
比如我们以一个“下载应用领红包”的活动为例。预设的用户的行为路径是:用户首先进入【红包首页】,发现最新的红包活动“下载应用,领取红包”,点击进入【红包活动页】,根据提示跳转到【应用下载页】,选择自己感兴趣的应用下载,完成后,进入【提现页面】领取活动奖励。从上面描述的场景中,我们可以提取出以下关键的四步。
图3.1 “下载应用领红包”活动步骤
3.3 确定漏斗的时间区间和周期
这里多了一个时间区间的概念,与前文介绍的周期容易混淆。一般来说,此类数据的数仓表是按照时间分区的。所以选择时间区间,本质就是选择要计算的数据范围。
周期是指一个漏斗从第一步流转到最后一步的时间限制,即是用来界定怎样才是一个完整的漏斗。在本例中,我们按照天为周期进行处理,选择时间区间为“2021-05-27”、“2021-05-28”、“2021-05-29”。
3.4 漏斗数据的展示
依据我们设计的漏斗模型(具体模型设计,下文会提及),可以计算出下表的数据:
表3.1 “下载应用领红包”活动分步数据
以表3.1中2021-05-27日的数据为例,触达第一步“红包首页”的用户数量为150,000,在同一天内同时触发第一步“红包首页”和第二步“红包活动页”的人数为11,700。其他数据的含义以此类推。
将表3.1中的数据每步按照日期加起来,就得到2021-05-27至2021-05-29日数据的漏斗图(图3.2)。
从中可以直观的反应出用户在“红包首页”、“红包活动页”、“应用下载页”、“提现页”四步中每一步的人数和转化率。
比如,触达“红包首页”页面的人数为400,000,经过”红包首页“,触达”红包活动页“页面的人数为30,000。则这两个阶段的转化率为:30,000÷400,000=7.5%。
通过对各个阶段人数和转化率的比对,就能比较直观的发现我们这个 “下载应用领红包”的活动用户流失的环节所在,并以此排查原因和优化各个环节。
图 3.2 “下载应用领红包”活动漏斗图
四、整体功能设计及漏斗分析模型的实现
4.1 功能整体架构设计
图 4.1 漏斗分析整体架构设计
整体工程主要分为配置、计算、存储三阶段。
(1)配置
此阶段主要是工程端的后台服务实现。用户在前端按照自身需求设置漏斗类型、漏斗步骤、筛选条件、时间区间和周期等配置。后台服务收到配置请求后,依据漏斗类型选择不同任务组装器进行任务的组装。
其中,漏斗类型是无序漏斗使用的Hive SQL 任务组装器,而更加复杂的有序漏斗可以使用 Spark任务组装器。组装后生成的任务包含了漏斗模型的计算逻辑,比如 Hive SQL或者 Spark 任务。
(2)计算
平台根据接收到的任务的类型,选择Hive或者 Spark引擎进行分析计算。计算结果同步到 mysql 或者ClickHouse集群。
(3)存储
结果集持久化到数据库中,可通过后台服务展示给用户。
4.2 无序漏斗实现逻辑
无序漏斗并不限制其多个步骤之间的发生顺序,只要在限定的周期内完成即可。
在模型的设计上,采用的思想是:
在一个周期内,按照步骤顺序依次计算漏斗每一步骤的人数,并且下一层的计算的人群范围要等于上一次计算完成的人群范围,通过每一步的人群范围可以计算出想要的指标,比如每步的人数(uv)或者访问量(pv)。
如图4.2 所示。其中,圈选的人群为每一步的触达的人数,计算的结果集就是基于此人群得到计算结果。步骤1的圈选人群会作为步骤2漏斗计算的一个筛选条件,参与后续计算。依次类推完成漏斗的每一步计算。最终汇集每一步的计算结果集形成类似于表3.1 的结果数据。
图4.2 无序漏斗计算逻辑
4.3 有序漏斗实现逻辑
有序漏斗顾名思义,将严格漏斗每步之间的顺序。整个实现逻辑可分为以下几步:
(1)获取规定时间区间内的数据集。
为了方便讲解,示例数据如下图所示,其中,day为数据上报的时间,userId为用户唯一标识,event为事件,event_time为事件发生时间。
(2)按照漏斗步骤计算每行数据处于的漏斗步骤。
假设需要统计分析的漏斗步骤为:“启动”->“首页”->“详情”。‘“启动”标记为1,“首页”标记为2,“详情”标记为3,记录在event_step字段上。
(3)对上述数据进行处理,得到每个用户在当天有序的事件上报列表。
将上述数据按照day,userId分组,按event\\_time顺序,分别求取event\\_step和event\\_time的有序集合,并根据event\\_step获取漏斗触达的最大深度,记为level,如下:
(4)计算每一步漏斗的人数。
按照day与level分组计算每一步漏斗的人数,也是是每个level的uv。
需要注意的是,因为计算的是每一步漏斗的人数,所以步骤与步骤之间人数是没有交集的,但事实上,根据有序漏斗的计算逻辑,触达漏斗后面的步骤,一会触达其前面的漏斗步骤。
所以,前面的步骤一定要加上其后所有步骤的的人数,才是该步真正的人数。如上面的例子,对于2021-05-01的数据,level=1的uv为1,level=2的uv为0,level=3的uv为1,所以level=1实际总人数为三步人数之和,也就是2。依次类推,由此可以得到所有步骤真正的总人数。
4.4 存在的问题与下一步优化的方向
问题:现阶段用户通过自定义的配置,生成相应的Spark或者Hive任务计算出模型的结果并生成报表,进而展示给用户。这样的流程在提供给用户灵活的配置和个性化的查询的同时,兼顾了节约存储资源。美中不足的是报表的生成过程,依然需要耗费一定的时间成本,尤其是有序漏斗采用了Spark计算,对于队列资源也会产生较大的消耗。这点在用户短时间创建大量的分析报表时,体现的尤为明显。
优化方向:将一定时期内的相关的数仓数据同步到ClickHouse,依托ClickHouse强大的即时计算和分析能力,为用户提供所查即所得的使用体验。用户可以根据自身业务需求选择即时查询或者离线报表。例如,比如需要大量组合各类条件进行对比分析的可以选择即时模块。需要长期观察的报表可以选择离线的例行报表。这样就达到的存储和查询效率的平衡。
下面,就对漏斗模型在ClickHouse上的应用做一些探索。
五、基于 ClickHouse 的漏斗分析模型
5.1 主要函数介绍
(1)windowFunnel(window, \\[mode, \\[mode, ... \\]\\])(timestamp, cond1, cond2, ..., condN)定义:在所定义的滑动窗口内,依次检索事件链条。函数在这个事件连上触及的事件的最大数量。
补充:
① 该函数检索到事件在窗口内的第一个事件,则将事件计数器设置为1,此时就是滑动窗口的启动时刻。
② 如果来自链的事件在窗口内顺序发生,则计数器递增,如果事件序列终端,则计数器不会增加。
③ 如果数据在不同的完成点具有多个事件链,则该函数将仅输出最长链的大小。
参数:
①【timestamp】 :表中代表时间的列。函数会按照这个时间排序
② 【cond】:事件链的约束条件
③【window】:滑动窗口的长度,表示首尾两个事件条件的间隙。单位依据timestamp的参数而定。即:timestamp of cond1 <= timestamp of cond2 <= ... <= timestamp of condN <= timestamp of cond1 + window
④ 【mode】:可选的一些配置:
【strict】: 事件链中,如果有事件是不唯一的,则重复的事件的将被排除,同时函数停止计算。
【strict_orde】:事件链中的事件,要严格保证先后次序。
【strict_increase】:事件链的中事件,其事件戳要保持完全递增。
(2)arrayWithConstant(length,param)定义:生成一个指定长度的数组
参数:
① length:数组长度
② param:填充字段
例:
SQL:
select arrayWithConstant(3,1);
Result:
arrayWithConstant(3, 1)
[1,1,1]
(3)arrayEnumerate(arr)定义:返回数组下标
参数:arr:数组
例:
SQL:
select arrayEnumerate([11,22,33]);
Result:
arrayEnumerate([11, 22, 33])
[1,2,3]
(4)groupArray(x)定义:创建数组
例:
SQL:
select groupArray(1);
Result:
groupArray(1)
[1]
(5)arrayCount(\\[func,\\] arr1)定义:返回数组中符合函数func的元素的数量
参数:
① func:lambda表达式
② arr1:数组
例:
SQL:
select arrayCount(x-> x!=1,[11,22,33]);
Result:
arrayCount(lambda(tuple(x), notEquals(x, 1)), [11, 22, 33])
3
(6)hasAll(set, subset)定义:检查一个数组是否是另一个数组的子集,如果是就返回1
参数:
① set:具有一组元素的任何类型的数组。
② subset:任何类型的数组,其元素应该被测试为set的子集。
例:
SQL:
select hasAll([11,22,33], [11]);
Result:
hasAll([11, 22, 33], [11])
1
5.2 模型构建过程
5.2.1 数据准备
为了更加清晰的讲解整个过程,我们举一个例子演示一下整个过程。
首先构建一个ClickHouse表funnel_test,包含用户唯一标识userId,事件名称event,事件发生日期day。
建表语句如下:
create table funnel_test
(
userId String,
event String,
day DateTime
)
engine = MergeTree PARTITION BY userId
ORDER BY xxHash32(userId);
插入测试数据:
insert into funnel_test values(1,启动,2021-05-01 11:00:00);
insert into funnel_test values(1,首页,2021-05-01 11:10:00);
insert into funnel_test values(1,详情,2021-05-01 11:20:00);
insert into funnel_test values(1,浏览,2021-05-01 11:30:00);
insert into funnel_test values(1,下载,2021-05-01 11:40:00);
insert into funnel_test values(2,启动,2021-05-02 11:00:00);
insert into funnel_test values(2,首页,2021-05-02 11:10:00);
insert into funnel_test values(2常见用户行为分析模型:漏斗分析模型