TDEM 归因算法揭秘, 挽回将要流逝的用户

2021-02-09 20:38:04 浏览数 (1)

何来因果 ?

因果 源于时间的不可逆。

在我们生活的世界, 很多事情一旦发生便不可撤销,例如亲人的去世、商业活动的失败 ...

在发生这些事情的同时, 往往有一些前兆, 例如地震前兆为 动物异常活动, 井水陡涨陡落 等等,我们迫切希望预知到即将到来的危险,并且提前做好防范。

于是,我们创造出 因果 一词,代指人们对于渴望更早预知将要发生的 事实

但是, 请注意 的定义一般明确,但 可以有丰富的解释。

以地震为例, 动物异常活动 并不是地震的原因, 事实上 动物异常活动 是地震的级连 结果。但是观察到 动物异常活动 又确实可以提早防范地震,因为在时间上地震到来晚于 动物异常活动

现在我们知道 地壳岩层受力后快速破裂错动 会造成 地震, 这是一个更合理的,因为 地壳岩层破裂错动 在时间上早于 动物异常活动

但是,又要发问: 地壳岩层破裂错动 的原因是什么呢 ? 其实这是一个无穷无尽的过程,并且多种原因又会错综复杂交织在一起,不出100次的连续发问就可以回溯到宇宙大爆炸。

但一个原则是: 应该与实际意义结合解释,过早的不具备实际可操作性, 过晚的因又来不及对进行干涉。

综上所属:

  • 为时序发生的一系列事件, 必须早于
  • 可以不止一种, 并且寻找原因的征途是没有止境的
  • 但只要可以发现早于 ,并且可以及时干涉 ,这样的 便是有意义的
  • 如果时间是可逆的,不存在因果关系

因果关系之梯

the-ladder-of-causation.pngthe-ladder-of-causation.png

图灵奖得主 Judea Pearl 在 《The Book Of Why》 一书中为我们展示了 "因果关系之梯"。

其中分为了三个层级:

  • 关联 (association): 也是当前机器学习主要面向的领域, 对于给定的一组变量, 探索目标变量与其余变量的相关性,以进一步进行预测。
  • 干预 (intervention): 通过进一步干预, 确定原因, 为了克服 关联的弊端, 高相关性不一定是, 有可能是, 而真正的不存在于自变量中
  • 反事实推断 (counterfactuals): 因为实际情况, 无法执行干预(例如GDP根因分析不能故意去干预降低GDP,损失过大), 需要靠 已有相关知识 进行逻辑推断。

一个最主要的概念区别是: 相关性高 不代表是 原因

一个著名的例子是: 冰激淋销量与犯罪量呈现高度相关,推断: 应该禁止冰激淋销售降低犯罪率。

但是进一步思考: 气温升高时, 人心情浮躁可能才是更可靠的原因。

但这不是问题的终点。气温升高时, 为何人会心情浮躁, 是基因的作用嘛 ? 是否去除掉高温使人浮躁的基因是最终解决方案。

但进一步思考: 高温使人浮躁, 是否是对人的一种保护机制,避免人长期处于对身体有害的温度中。

为了解答上面所有的问题, 需要进行反复的干预实验,这些实验不会天然存在于自然中。

自然永远是单向演化,而干预实验实际上是人工引发与自然演化的不一致来观察结果, 进而验证假设。

TDEM 中的归因分析

对某项事实, 尝试寻找原因的过程便为归因。

归因有重要的商业意义,任何商业行为都有目标, 而目标最终成功/失败与多种因素相关,了解商业目标的成功/失败与何种因素相关有助于实现商业决策。

TDEM 承载了多种应用数据, 包括:

  • 用户性能事件, 例如 卡顿、Crash、网络错误 ...
  • 用户操作记录,例如 进入的页面,点击的按钮
  • 衍生指标: DAU/WAU/流失率 ...

以上数据就是 TDEM 目前的认知边界,我们无法做到超越认知边界以外的事情,因此归因局限在上述数据范围。

我们尝试回答像这样的问题:

  • 什么 性能类因素 造成了 用户流失 ?
  • 什么 性能类因素 造成了 订单转化率低 ?

当然, 如果有更多非性能类因素可以加入到推断中会有更全面的归因结果(例如运营活动以及设计改版), 但就目前来讲,我们可以提供的只有 性能类因素 的归因

showcase.pngshowcase.png

归因分析业界算法

  • Adtributor, 参考 Adtributor: Revenue Debugging in Advertising Systems
  • JS散度, 参考 DAU归因分析之JS散度
  • Squeeze, 参考 Generic and Robust Localization of Multi-Dimensional Root Causes

TDEM 归因分析实现

许多上述的业界算法都是尝试在多维空间中,寻找异常维度组合。

TDEM 数据特征

  • 维度多样, 几十种归因维度并且会持续增加
  • 数据量级大, 原始数据量级在在十亿以上
  • 作为 Sass 平台, 接入多个产品, 这些产品是需要分开计算的

方案选型

考虑到数据量级以及低实时性需求,我们选择了大数据生态下的解决方案。

最终以 Spark MLib 提供的核心能力,选择了频繁度挖掘算法 FP-Growth 作为主力算法。

Spark MLib 提供的能力中,可作为归因还有 Gradient-boosted tree classifier , GBT 在 Spark MLib 提供的分类算法中,在实际数据测试中有最好的 areaUnderROC 指标。并且有良好的可解释性。

但是实测中, GBT 算法中, 性能指标的 Feature Importances 普遍偏低,并且预测的准确率低于 70%,这给结果的可解释性带来了困难。

我们思路转向了: 是否可以找出性能因素有更高支持度的场景,例如: 广东电信的用户中, 网络错误是用户流失的一大原因 (可能产品在广东电信场景下有运营问题)。

我们最终使用 FP-Growth,尝试寻找在特定场景下的归因。

TDEM 归因流程

TDEM-Attribution.pngTDEM-Attribution.png

如上图所示, 归因分为了 6 个步骤:

  1. 计算 Features, 用户为维度, 每天计算一次, Features 包括用户属性(如运营商/机型/地域)及归因源(如卡顿次数/Crash次数/启动平均耗时)
  2. 将所有字段分为 4 个部分, 命名空间 / 用户属性 / 归因源 / 归因目标
    • 归因目标, 此次归因分析的目标,例如用户流失,订单转化失败 ...
    • 命名空间, 每个命名空间中的数据是独立计算的, 当前命名空间为 AppID, 即每个产品的归因在逻辑上是不相互影响
    • 用户属性, 先验经验不能作为归因的字段, 例如: 机型/地域/运营商 这些,这些不是最终原因,但我们把这些字段作为用户分组字段
    • 归因源, 先验经验中,可以作为归因的字段,例如: Crash 次数/卡顿次数/启动耗时 ...
  3. 将”归因源”字段中值类型的转为 Label: 高/中/低,并筛选 Label
    • 因为 FP-Growth 算法只接受 Category,不接受 Number
    • 转为 Label 后,按照先验经验,只保留会造成用户体验损失的 Label, 例如 卡顿次数:少 不会作为归因, 而只有 卡顿次数:多 才能作为归因
  4. 筛选命中归因目标的用户, 以归因源用户属性字段作为 Items, 进行 fpGrowth 频繁度挖掘
    • 目的是寻找归因目标下,有哪些模式频繁发生
  5. 对产生的频繁集, 筛选含有1个归因源的频繁集, 将频繁集中的用户属性集合定义为 用户分组
    • 为何是 1 个 归因源 而不是 2 个或更多 ? 首先 1 个归因源 支持度大于 2 个及以上
    • 1 个归因源 代表的是最主要归因
  6. 对每个命名空间下的所有 用户分组, 分别计算每个分组的下属指标
    • 归因目标发生次数
    • 归因命中次数: 归因目标发生时, 归因发生次数
    • 支持度: 归因命中次数 / 归因目标发生次数

TDEM 归因架构

TDEM-Attribution-dataflow.pngTDEM-Attribution-dataflow.png

简化架构如上图所示:

  • Spark SQL 计算 Features
  • Spark MLib 计算归因并导出到 ES
  • 数据存储在 HDFS/DeltaLake
  • 每天离线计算一次

TDEM 归因实现细节

  • 资源允许时, 将 user_features cache 到内存, 在需要每个产品单独计算时提高 Filter 性能
  • 尽量减少需要分别每个产品单独计算的部分, 在进行 FP-Growth 分产品计算完成后立即 Union, 后续指标计算不再分产品
  • 每个产品会产生成百上千个 用户分组,计算每个用户分组的指标时, 可以先计算每个用户分别属于哪些分组
  • 计算每个用户分别属于哪些分组时, 可以将所有分组使用 broadcast 变量广播后, 使用 Spark UDF 进行计算
  • 计算完 每个用户属于的分组后, 对分组列表进行 explode 进行后续指标计算
  • 调节 Partition 个数, 避免 OOM
  • 计算 Feature Label 时, 需要事先确定数十个维度的 25分位/75分位, 此过程可能发生 OOM, 可以抽样计算

优势与局限性

TDEM 实现的归因, 理论上的优势在于先验经验的加入。

在先验经验上, 一些不能作为 的部分提前被剔除, 让最终结果减少噪声。

此外, 依靠频繁模式而非多维空间下钻, 可以规避 维度灾难

局限性:

  • 频繁原因之间还是有差别,缺乏足够的可解释性
  • 依然处在因果关系之梯的最底层: 关联, 而干涉需要进行A/B Test,并且性能问题的干涉并不是非常简单可行

关于归因的想法,欢迎评论区探讨

欢迎接入 TDEM (原QAPM) 体验

0 人点赞