概览
KPI(关键绩效指标) 预测对于 Tubi 的业务非常关键,Tubi 的数据科学团队开发了一个非常稳健的系统来帮助设定公司的预算、内部和外部的目标以及当服务出现问题时能够帮助我们定位原因的异常检测机制。我们将在本文中讨论特定领域的可视化策略、支持预测模型的 Prophet [1](Facebook开源的时序预测框架)的背景,定制化的建模方法以及线上工作流程和评估技术。
为了更好地阐述我们为何开发出现有的预测模型,让我们首先来看一些用例。
===
应用:规划仪表盘
Tubi 的预测方法结合了统计工具和业务知识。需要提前指出的是,我们不将预测作为最终结果;这是因为我们不可能建立一个总是100%准确的完全客观的模型;但是通过 KPI 预测,我们可以更深入地了解我们的业务和数据。
我们的预测数据可视化在如下所示的交互式仪表盘上:
图1:当前月度总观看时长预测
这种可视化可能不是一看就懂的,但实际上给我们提供了非常多有用的信息。y 轴表示指标值,而 x 轴表示预测日期。橙色立柱表示 x 轴对应日期过去一个月的的总观看时长。这意味着图表上的所有橙色立柱都表示相同长度时间段的预测,只是在不同的日期生成。换句话说,这是个典型的时间序列预测的例子。
此外,黑点表示的是前14天在日历月预测值的移动平均值。这是从视觉上消除一些每日波动的便捷方法,在不确定性很高的时期尤其有用,例如当我们公司遇到不确定的事件,而这些事件极大地改变了用户或广告客户的日常行为。
灰色线代表95%的置信区间;随着我们接近日历月末,这些界限通常会收敛,因为预计值会包含越来越多的历史真实值和更少的预计值。但是,我们不能保证置信区间随时间单调减少,因为某些时间段,例如涉及更复杂的季节性组合的时间段或总体上涉及度量值大变化的时间段(比如节假日)会比其他的时间段更加难以预测。
最后,设定目标后,将它们与预测一起作为水平线元素绘制。这样我们就有可比较的基准。
我们先预测每天的值,然后累计到日历月。我们每天会使用最新的数据重新生成预测。这是在这个时间点为止我们通过当时所有可获取信息做的最佳预测。我们通常使用当月和当季的预测。随着时间的行进,我们将已过去的天中的预测值逐步替换为实际值。
在仪表板上,我们可以直观地看到一个月之前的预测。相较于仅仅展示最新预测,展示历史预测有多个好处:首先,它可以帮助我们了解我们的预测是如何随着时间和新数据变化的。当然,我们期望预测会随着新数据的变化而变化,但一个更加有用的监测阈值是置信区间的宽度是收敛还是发散,或者何时移动平均线跌出置信区间。是否超出阈值是我们需要重新审视模型的信号:如果是特殊事件导致指标发生变化,我们可以增加一个节假日参数;如果是由季节性调整不当造成的,我们可以相应地调整模型输入和参数。
此外,拥有稳定的历史预测记录可以提高利益相关者对预测可靠性的信心。我们已经了解到,开发预测模型最关键和最棘手的部分可能是获得体制认可,还有什么比证明你的预测在历史上是稳定和准确的更好的方法呢。
===
应用:异常检测
预测的另一个重要用途是指标异常检测。让我们来看下如下所示的预测指标和实际指标对比图:
图2:2020年4月收入的预测值与实际值对比
Tubi 的项目负责人密切关注 KPI 值,并认真研究每周下降的情况。一旦排除了数据质量问题,下一步便是将反事实的预测与实际指标值进行比较。这样,我们可以扣除指标值符合预期的变化,例如由于周期性的季节性因素或非周期性的特殊事件(例如竞品的发布)所引起的变化。
在上述情况下,由于我们正在经历的新冠肺炎疫情带来的经济影响,我们观察到广告主投放正开始减少。这是一个导致重大不确定性的黑天鹅事件的绝佳示例。用经济学的术语来说,预测误差的来源是风险和不确定性。风险是指我们可能不知道结果但对概率有很好的了解,例如掷骰子。每个掷骰的结果是随机的,但我们知道它一定落在1到6之间,不可能是14或-2。而不确定性是指从一开始我们就不知道事件发生的概率。我们可能会做出一些假设,但是我们没有量化此事件对未来事物影响的客观方法。我们所能做的最大努力是当这些事件发生时好好研究利用,以便当同样的情形复现时我们可以更好地规划。
方法论—使用 Prophet 库
Prophet 是 Facebook 发布的开源预测库。它非常适合预测时间序列的数据,而且定义了一套灵活的 API,其内部包含了复杂的数学公式和术语。
Prophet 使用 STAN [2] 统计库作为后端,用类似 GAM(广义加性模型)的方式分解时间序列。这个模型用时间作为回归因子,加上表示趋势、周期季节性(比如每周或每年的变化模式)、非周期时间(这特指库里的假期参数)等等参数,以及一个表示方差的误差项。
这个库还带有交叉验证和诊断功能,通过扩展我们还能获得更多高级功能。这也验证了库作者们经常间接提及“人工干预 [3]”开发思路:先通过可视化和诊断功能找到和暴露问题,再使用统计和领域知识解决问题。模拟的历史回测可作为交叉验证方法,以评估样本的准确性。除了诸如RMSE(均方根误差)和 MAPE(平均绝对百分比误差)之类的内置误差指标外,我们还添加了另一个与我们的关键用例更接近的误差指标:月度误差百分比。我们将回测间隔设置为30天,并逐步计算30天的预测误差。累积误差占实际值的百分比是我们在模型开发期间的关键准确度指标。
我们开发的另一种启发式方法是并行化的超参数优化功能。使用 scikit ParameterGrid [4]数据结构定义超参空间,我们使用模拟的历史回测和月度误差百分比误差指标来训练最好的模型,从而实现一种简单的网格搜索算法来执行详尽的搜索。此外,我们利用 joblib [5]并行化库来展开循环,利用多核处理来加快搜索速度。虽然可以使用更智能的算法(例如随机搜索或模拟退火)极大地提高搜索效率,但超参数优化既不是瓶颈,也不是我们模型开发中的关键组成部分。
尽管我们花了一些时间使用超参优化功能来扩展 Prophet,但我们不建议一股脑儿将模型扔到大量参数中训练从中找出准确度最高的模型,必要的反思还是需要的。时间序列交叉验证是比较复杂的,样本拟合最好的模型往往对新数据的泛化能力不足。单靠超参优化可能更快导致过度拟合。
话虽如此,这个方法还是有其用武之地的。至少,对于有些间接影响模型的参数,这个方法可以感受到模型对于其不同值的反应。其中包括以下参数:
-
prior_scales(针对季节性):用几项傅里叶级数表示季节。项数越高,曲线越灵活,并且对时间序列变化的反应越快。
-
changepoint_prior_scale:与 prior_scales 类似,趋势拐点频率的变化率灵活性指标。
-
changepoint_end:训练时间序列数据中设定趋势变化的最新点。
然而对于季节性因素而言,我们可能应该先认真观察我们的时间序列数据,然后加上领域知识做出判断。例如,大多数人类活动遵循的是7天的周期;在我们的情况下,工作日的收视率往往较低,而周末则较高。我们能很明显看到我们的时间序列数据也具有类似的特征(以下所有的峰值表示周日):
图3:总观看时长时间序列
但是,在广告收入方面,通常是由数字营销预算驱动的,该预算每季度重置一次(请观察灰色竖线导致的明显定期变化):
图4:广告收入时间序列
===
特征工程
Prophet 库的另一个有用功能是它支持外源时间序列回归因子和特殊事件/节日。在构造这些输入特征时正确应用领域知识可以大大提高模型表现。
回归模型的一个有趣案例是我们销售团队将其作为收入的预测模型。从广义上讲,Tubi 的广告收入可分为两个部分:程序化(通过广告系统交易所促进的自动广告)和直接广告(我们销售团队与品牌直接签署的交易合同)。通过将销售团队的历史人数和计划中的未来人数编码为时间序列,我们能够定量表示不断增长的业务影响,来预测收入的直接组成部分。简而言之,通常更多的销售人员对应更多的直接的交易和收入。这也使我们可以在未来员工人数增长的各种情况下模拟未来收入的变化。
节假日是 Prophet 中的术语,用于非周期性事件,这些事件会极大地影响时间序列,例如有关 Tubi 的新内容或产品功能发布。这是与我们的商务和工程团队密切合作的绝佳机会,我们的商务团队将密切关注此类特殊事件,而工程团队将监控所有发布问题和系统崩溃。认真考虑此类事件可能会消除季节性和趋势曲线拟合中的噪声,从而可以找出模型变化的真正原因。模型一旦加上节假日参数后,它可以根据之前发生的情况训练学到的指标变化做出适当调整。
开发部署
我们的预测模型是用 PySpark 写的,采用 Airflow 调度。预测输出以 Pandas dataframes 的形式生成。这些数据以 parquet 格式保存在 AWS S3 中,之后我们使用 Redshift Spectrum 直接读取这些 S3 文件。为了避免大量访问我们的数据湖(随着时间的推移会增加大量成本),我们使用叫做 DBT的框架 [6]将这些数据存储到我们的数据仓库中。至此,我们已经可以通过 Redshift 访问这些数据,并且在仪表盘展示了。
模型评估
该项目的最后一步是对我们所做的预测进行回测和评分。尽管这与模型开发过程中进行的交叉验证误差计算相似,但不同之处在于,我们将使用修改后的评分指标,并将结果提供给相关人员查看。
每月总错误评分指标保持不变。但是,我们需要一个新的标准,该标准既考虑到置信区间,也能表示在预测日期开始之前我们的预测的可靠性。一个容易想到的方法是计算在置信区间内的预测值的占比。但是,我们的预测不一定使用相同的置信度:某些指标可能需要更保守地设置置信度。因此,我们为此采用了 brier score [7]指标,并在置信度上设置了概率:
Brier Score 损失函数
其中 N 是预测数,f 是分配给该预测的概率,o 是二进制的实际结果。
为什么要让我们的利益相关者公开看到预测得分?我们坚信主人翁精神和责任制。隐藏预测并仅在结果准确时公布结果而获得赞扬是最容易的,但这将阻碍迭代式改进。通过对模型的性能透明,我们证明了我们有动力继续改进模型。这有助于建立对我们预测的信任和支持。此外,我们针对这些指标设置了报警,一旦有指标显著降低我们能马上知晓并处理。
模型推广
在文章的前面,我们已经描述了展示稳定和准确的预测历史是建立利益相关者对模型信任的强大工具。这个主题可以很容易地单独写成一篇文章,不过我将在这里列出一些主要的经验教训:
-
设定期望:很难对模型充满信心,但很容易失去信心。尽管可能有充分的理由说明结果不理想,但只有一个或两个预测失败(真实的或感知的)会导致利益相关者放弃你的方法。确保清楚地传达模型的功能,并且不能保证预测,因为预测会因许多原因而改变,其中一些原因已在本文中进行了阐述。
-
不断重复:即使你对模型进行了出色的介绍,利益相关者也不一定会一次就接受或记住。你必须不断地宣传模型,直到达到一定数量的机构认可为止。之后,你的模型将成为解决特定类型问题的默认选择。
-
通过教育和相互学习进行布道:不要将你的模型介绍给利益相关者作为技术上的黑匣子;而是采取教育和协作的方式。与利益相关者会面,了解他们现有的预测工作流程,并评估是否存在相互学习的机会。解释你的模型假设和输入是什么,并建议领域专家提供反馈。这些讨论可能也会使得你自己的特征工程取得突破进展。
展望
预测模型最初是为帮助我们的产品团队进行报表生成,目标设定和异常检测而开发的,但它们已逐渐在整个公司中得到广泛采用。该项目软件设计的模块化性质确保了应用领域的扩展既简单又有效。
通过回测和评估,我们看到我们的模型性能随着时间的推移稳步提高,一个例外是由于新冠肺炎疫情的影响,用户和广告主在模型初期行为有些异常。预测不能想当然认为是有保证的,但是终归这些是我们的业务模型,我们不可能完全考虑到所有数据和细节。但是,关键是我们将预测作为一种工具来帮助我们了解我们的业务并指导我们的决策,从而使分析人员与模型之间的协作比单个方法更好地达成业绩。
如果你是对解决这类挑战感兴趣的数据科学家,我们将很高兴收到你的来信!
**作者:TJ Jiang, Tubi Senior Data Scientist
**
译者:Mei Bai, Tubi Machine Learning Engineer
点击 “阅读原文” 查看英文版
[1]facebook.github.io/prophet/
[2]mc-stan.org/
[4]scikit-learn.org/stable/modu…
[5]joblib.readthedocs.io/en/latest/