压在数据分析同学身上的”三座大山”

最近跟数据分析同学闲聊,收集了一波数据分析同学被挑战的问题。比较有趣的是,不同部门的数据同学提的问题,很大部分问题是重叠的。问题简述如下:

1、这个数据为啥不一致,靠谱不靠谱?
2、计算为啥这么慢,跑一段sql的事情要这么久么
3、筛选维度为啥不能自由组合,多选+汇总+展开都支持
4、数据需求就跑sql,为啥那么慢呢
5、虽然没数据,逻辑你先写吧
6、我要这个数据,下午给我
7、我们什么时候搞点机器学习项目
8、自己模仿跑sql,挑战结果不一致
9、报表数据不能跨年查询
10、报表上线后很长一段时间都会被反复追问口径和逻辑,用的哪个表,怎么算的
11、希望在报表侧自由选时间段并且数据是时间段内按人数去重汇总
...

有些问题比较类似,进行了合并,并命名为压在数据分析同学身上的"三座大山",再简述如下:

数据计算慢

1、查询慢,这个报表能不能用,跨年查询卡死了
2、计算慢,日报还没推送,今天还没出,为啥这么慢
3、实现慢,这个需求只要简单跑个sql,为啥那么慢

数据维度繁杂

1、导数支持,要汇总也要细分,更要明细,报表麻烦支持下
2、实时去重,希望根据不同时间,去重统计UV
3、多维支持,再加几个维度吧,现在十多个维度还有点少

数据准确性

1、指标差异,这2个指标看起来一样,数值对不上
2、对数差异,模仿跑了下sql,结果不一致,给我解释解释
3、逻辑验证,逻辑复杂,计算逻辑和口径无法确认准确性

暂不讨论解决方案,要完整的解决这些问题 ,底层计算方案、BI方案是需要review的。

不过,我们从中可以窥探出,需求方理解的数据需求实现,特别是PB数据需求实现,是有理解偏差的。可能很多产品或者前端同学对“大数据”意味着什么,并没有概念,所以需求就可能想当然。

简单挑几个点讲讲。

“数据计算慢”的问题,如果需求方说:“帮忙跑个sql”,并且附带一句:“这个需求很简单”,一般的数据分析师会默念或者画圈圈。“实现慢”是按需求者视角,不考虑实现者的需求并行负担。另外的真正的“计算慢”的问题一般跟实现相关,数据倾斜的概率比较大,数据分析师是要好好解决的。

“数据维度”的问题,从开源的实现方案看,apache kylin可以部分解决"数据维度"的问题,但是多维度也是需要预先定义好的。

只要统计数据又要明细数据是见过最多的统计需求,问题是,统计需求又要明细,那么意味着原始数据存储的量是特别大,必要性要好好评估的。往往指标数据、监控数据或者原始记录的需求放一起是不对。

“数据准确性”的问题,当然,准确性是数据分析的基础要求,往往挑战来自于不同的报表实现,过多的特殊逻辑导致。整个数据的DWS层需要统一管理,这样应用层只取一处数据可以缓解的这个问题。

压在数据分析同学身上的”三座大山”

聊一聊商业分析的主要关注点

商业,总体上关注成本和收入,钱是安身立命之本,所以从宏观维度看,成本构成、收入贡献是核心关注点,比如资产负载表、利润表、现金流量表。

从执行层面,可以继续细化,如下图:

  • 商家Business、用户Customer、客户关系CRM
  • 渠道Channels
  • 关键活动、核心资源、核心伙伴
  • CRM

    每个商业活动,我们希望不是一锤子买卖,所以客户关系建立和维系是很重要的,客户的发生和维系需要渠道能力支撑。

    CRM主要关注三个方面:
    1、用户信息建立,用户信息化
    2、关键活动记录,用户个性化
    3、用户关系管理,用户关怀

    渠道Channels

    渠道,包含收入渠道、支出渠道,包含各种触达用户的各种工具,比如:小程序、APP、PC、WEB、线下柜台。不同渠道成本、收入的效率是不一样的。渠道的种类和数量决定了商业规模,成本、收入的效率决定商业是否能否持续开展。

    渠道的管理也是需要不断拓展和维系的。用户、渠道、CRM我们可以统称为3C。渠道的关注三个主题:降本、提效、增收。不同的考核对象关注不同的指标。

    关键活动

    买货、卖货,需要很多的活动去开展,即拓展和运营。而拓展和运营受限于我们的所拥有的核心资源、核心伙伴。我们可以统称三者为3K。

    关键活动主要关注:
    1、活动目标
    2、投入成本
    3、效果情况

    核心资源、核心伙伴

    核心资源和核心伙伴是发展壮大的主要因素,商业活动不可能一人成事。每个关键活动,需要供应商、合作方协作推动。

    核心资源即竞争力,主要关注:
    1、研发资源
    2、客户资源
    3、品牌价值

    核心伙伴,主要考虑合作商家情况,比如供应商、开发商。

    聊一聊商业分析的主要关注点

    数据分析基础——关于埋点和数据的生成

    数据分析一般从ETL开始,数据分析师一般较少关注埋点和数据的生成、存储。我们补个缺,聊一聊数据埋点相关细节。希望看完本文之后你可以更好的跟前端、产品同学battle。

    一、埋点类型

    从数据生成方式,我们可以分为三类:
    1、全自动埋点
    2、半自动埋点
    3、手动埋点

    为了理解这三种埋点类型,我们先了解下技术背景。一般可以把一个页面或者模块的可视化生命周期抽象为:

    def init()    # 初始化
    def onShow()  # 可见
    def onHide()  # 隐藏到后台
    def onClose() # 关闭退出

    从程序实现角度,埋点的处理可以插入这4个可视化周期之一,这4个周期主要生成曝光、启动等非用户主动操作的指标。而曝光指标埋点上报写在onShow()中,即在页面渲染完上报。有一个关键点,手速太快曝光过多对数据有一定影响,从经验角度,需要卡延迟,比如显示500毫秒以上该模块曝光才上报。

    而用户行为产生一般有以下交互场景:

    def onHover()       # 获焦点
    def onClick()       # 点击
    def onLongTouch()   #  长按点击
    def onDoubleClick() # 双击

    从统计角度,一般只需获焦、点击行为,特别在移动端场景基本没有长按、双击场景,所以用户行为主要贡献点击类指标,通过点击的模块衍生出兴趣相关的指标。

    回来讲三种埋点类型:
    1、全自动埋点
    全自动意味着埋点求全,因为不知道你要什么,所以给你所有。埋点sdk通过代码插桩的方式mix in上述的几个可视化和点击事件。根据控件树,获取控件id和上下文的控件id,进行全量上报。

    2、半自动埋点
    只对可完全抽象的场景进行自动化埋点,比如主要页面和入口的曝光、点击。由于业务场景一般涉及自定义参数,比如渠道、活动、内容、场景等程序无法自动生成的上报进行自定义埋点开发。

    3、手动埋点
    即根据产品需求,case by case埋点。

    所有的埋点数据最后需要解析回来,也就是数据解读,全自动埋点解放了前端人力,但数据解读比较困难,并且带来的问题是控件id随着前端的重构会变得十分脆弱,ETL逻辑维护困难;而手动埋点又过于死板。相对合理的方式是:半自动埋点。

    然而,我们仍然需要优化埋点管理,我们需要抽象出脱离前端模块实现的埋点方案,即前端模块重构、下线不至于所有后续的指标统计推倒重来。下面我们继续聊怎么做到这一点。

    可以从4w来阐述,即who、where、when、what

    二、who: 我是谁

    我是谁包含:用户是谁、模块是谁。
    用户是谁,包含:appid、openid、sessionid,即app标识、用户标识、会话临时标识。更进一步,除了用户 标识,关于“用户是谁”可以包含终端信息,比如:终端品牌、型号、硬件id、imei等。

    模块是谁,包含:页面、模块两个维度,遵从树状结构设计,需要知道来源是谁、去向是谁。一个页面一般有多个模块,每个模又细分多种元素,所以模块需要统一的标识,前面说到前端控件ID存在重构丢失、重复的问题的,所以每个控件的生成需要从类对象的维度统一抽象,即定义抽象基类:

    class base_module
    {
         var pre_page     # 上一级页面
         var next_page    # 下一级页面
         var element_id   # 模块id
    }

    模块ID和模块的上下文是很关键的信息,ID不单单只是一个标记,ID隐含的信息可以包括:
    1、归属的页面
    2、归属的模块
    3、元素标识
    从这三个层面看,ID是一个多级结构,是有规则生成的,可以参考以下结构:

        页面.模块.元素

    由于数据上报和存储统一utf8存储,可以直接用中文定义模块id,或者换成字母递增:

        首页-热门推荐-运营位
        a1.b1.c1

    上面两者的定义是等效的。另外pre_page、next_page直接取a1这一维度的信息。归属的模块提取a1.b1这个维度的信息,a1.b1.c1则可定位到元素。如果模块之间嵌套多个模块,原则上可以继续拆分到4级,即a1.b1.c1.d1,过多层级需要考虑实际的使用场景。

    三、where: 在哪里

    who从某种意义上解决了部分的where的问题,从产品维度一般where指的是模块的位置信息。大部分的产品为tab页面,即多个页面,页面内容相似,页面内分为多个楼层,每个楼层有多个区块,可以定义以下结构:

    class base_module
    {
         var tab_idx         # tab页面id或者顺序,可缺省为0
         var pos_x           # 区块位置
         var pos_y           # 楼层位置
    }

    每个楼层可能出现两行,位置pos_x递增即可。位置信息可用于热力图绘制。

    where信息又包含用户或者设备所在的地域信息,即ip或者经纬度信息:

    class base_module
    {
         var ip              # ip,粗粒度的用户位置
         var longitude       # 经度
         var latitude        # 维度
    }

    三、when: 什么时候发生

    when是时间信息,从数据维度有2种时间:用户侧产生的时间、数据到达服务器的时间。分别记录即可。

    四、what: 内容是什么

    模块是个容器,可以承载文本、图片、多媒体,模块也可以只是一个简单的占位符。我们统称为内容,那么内容可以包含content-type、content_id。

    class base_module
    {
         var content-type     # 内容类型
         var content_id       # 内容id或者叫资源id
    }

    内容是个业务相关的,一般由业务cgi直接下发,也即前端、后台根据协议直接透传上报内容信息,可以是json结构。内容id涉及到内容分类或者更多的结构化分类信息 ,一般通过业务DB关联提取。

    综上所述,我们得到,数据埋点的通用结构如下:

    class base_module
    {
        var app_id
        var open_id
        var session_id
    
        var device_id
        var device_model
        var device_imei
    
        var pre_page         # 上一级页面
         var next_page       # 下一级页面
         var element_id      # 模块id
    
         var tab_idx         # tab页面id或者顺序,可缺省为0
         var pos_x           # 区块位置
         var pos_y           # 楼层位置
         var ip              # ip,粗粒度的用户位置
         var longitude       # 经度
         var latitude        # 维度
    
         var content-type    # 内容类型
         var content_id      # 内容id或者叫资源id
    
         var time_stamp      # 前端数据时间
    }

    五、不同终端的埋点问题

    现在的应用大概可以分为五种:h5、pc、安卓、ios、小程序。不同的终端类型获取数据的能力是有限的,比如:imei是移动端特有,h5、小程序一般获取不了硬件id,用户id体系较弱。安卓体系可以获取的信息最全,但安卓定制化较高,不同厂商之间硬件id可能重复。

    六、埋点数据质量

    统一的接口规范,那么埋点数据才有可测性,也减少不同人员之间的沟通成本。数据的质量从行和列两个维度看,“列”是约定定义集合,基本不动,可以自动化查是否缺漏。“行”即数据是否多报或者少报,这块是需要一个实时日志系统进行辅助验证的。该系统可根据openid白名单,实时反映数据上报情况即可。

    七、统一指标的设计

    埋点数据最终落地到数据集群,形成ods层,后续的指标计算基于该层进行二次封装。要实现统一指标计算,上述的埋点数据需要进一步抽象,可以抽象为:时间、维度、度量。

    时间:所有数据的计算是一定带有时间的,比如:分钟、天、周、月
    维度:即分类,可以有渠道分类、区块分类、用户群分类
    度量:大抵可以分为计数度量、求和度量、人数度量

    如果时间明确、维度一致、度量固定,是可以实现一个统一的指标计算系统的。当应用方需要使用到哪一方面的数据,直接提取即可。

    数据分析基础——关于埋点和数据的生成

    用户画像的设计和构建流程

    针对APP埋点之后,你将不断收到各种各样的用户行为数据,为了更好的做用户运营,你需要把原始数据提取成“用户标签”,而用户标签化,即为用户画像的刻画。传统意义的用户画像,可以按生成方式,简单分为三类:

    • 基础属性:根据用户属性上报,直接提取,例如:年龄、性别、地域等人口属性
    • 统计属性:根据用户行为数据,聚类统计,基于一定的概率按时间因子衰减
    • 价值属性:根据多维度特征融合,算法预测,生成各种高潜用户属性,比如付费高潜、流失高潜,一般为概率模型

    上述描述的用户画像又怎么生成呢?从数据处理角度看,可以分为三个过程:

    • 基础数据处理,ods层数据建设
    • 画像中间数据ETL,行为偏好数据提取
    • 画像信息宽表建设,用户画像结果数据

    把上述步骤继续细化,我们可以得到:
    1、用户标签体系设计,技术人员跟业务资深人员,根据业务特点设计用户标签分类,即根据精细化运营目的设计标签
    2、埋点数据整理,设计好标签之后,数据开发跟前端开发一起设计埋点数据规范,只有数据埋点完备,用户行为才能完备
    3、多源数据拉通,一般不同数据源需要有统一的用户id,比如统一为微信小程序的openid
    4、数据融合 ,多种行为数据提取
    5、基于规则的标签提取、生成
    6、基于聚类分析结果的标签提取
    7、基于算法的特征挖掘,画像建模提取
    8、多标签合并,多个标签结果合并成统一的宽表
    9、标签质量分析、监控,及时发现标签缺失,有效监控标签质量

    最后,所有标签只是把用户逐步细化的过程,你还需要一个可以触达用户的系统,你还需要一批可以打动用户的营销策略。只有把用户细分,用合适的策略通过高效的触达渠道,才能达到精准运营的效果。

    用户画像的设计和构建流程

    聊一聊AB测试实验结果分析

    从事互联网工作的同学,对“AB测试”概念一定不会陌生,如果你觉得陌生,建议换一家互联网公司看看。
    AB测试流程上看,可简单分为三部:

    • 用户筛选
    • 实验策略
    • 结果分析

    前两部有比较标准的实现流程。
    用户筛选:比如账号随机、人群画像分层筛选的
    实验策略:一般会涉及一个实验系统

    前两步功能可能工程实践多一些,暂不讲述,今天讲讲——结果分析。

    假设你对一个app首页做了一个瀑布流优化,你拿到实验组、控制组(参照组)的CTR数据,“假设检验”流程如下:

    • H0:实验组CTR<=参照组CTR
    • H1:假设不成立,实验有效
    • P值:0.05

    我们可以得到实验组、参照组的均值方差,我们假定人数够多的情况下,是符合正态分布的,所以上述描述,可以转化为:
    1、随机抽取足够大的两组用户,分别统计CTR,求差值:
    ctr_diff = 实验组CTR - 参照组CTR
    ctr_diff 显然是符合正态分布的

    2、根据 ctr_diff,我们可以假设全局正态分布的均值0,方差=ctr_diff的方差
    3、所以根据1、2,可以计算得到p值

    p值小于0.05,你会选择上线新的瀑布流优化版本。流程上是OK的,但是可能存在问题。

    1、CTR高是否核心业务贡献就高,比如停留时长呢?支付转换呢?
    2、实验的时机,是否会出现人群偏差,比如寒暑假,自然学生人群占比可能多一点(年龄分布抽样可以解决部分问题)
    3、老用户的守旧倾斜(不接受新的变化),是否对结果有“否定作用”

    所以,你可能不能只选择CTR,首选,我们衡量的指标是多元化的,可以选择对业务KPI相关的核心指标进一步佐证。
    多指标的操作流程是:

    • 每组假设检验
    • 每组验证p值

    多组检验验证p值=0.05 是不合适的,容易产生type I error(阿尔法错误,“冒进”错误)
    所以Bonferroni提出了一种Bonferroni校正方法(Bonferroni Method),即一种降低p值的再检验方法:

    • p值/指标数量

    Bonferroni校正方法是一种较为严格的方法,如果能够拒绝原假设,那就放心上线吧。但是,宁愿错杀也不接受的,可能犯了type II error (贝塔错误,"保守"错误)
    Holm 提出了一种改进方法,较为融合,也即改进p值的对比方法,可参考:Holm–Bonferroni_method

    • 最小的p值和p值/指标数量,第二小的p值和p值/(指标数量-1)比较,以此类推
    聊一聊AB测试实验结果分析