Skip to content

使用统计分析处理时间序列中的异常检测

为指标设置警报并不总是那么简单。在某些情况下,简单的阈值效果很好,例如,监视设备上的磁盘空间。您只需将警报设置为剩余 10%,即可获得保障。跟踪服务器上的可用内存也是如此。

但是,如果我们需要监控网站上的用户行为之类的内容怎么办?想象一下,经营一家销售产品的网上商店。一种方法可能是设置每日销售额的最低阈值,并每天检查一次。但是,如果出现问题,您需要在几小时甚至几分钟内更快地发现问题怎么办?在这种情况下,静态阈值不会削减它,因为用户活动全天都在波动。这就是异常检测的用武之地。

img

异常检测到底是什么?它不依赖简单的规则,而是分析历史数据以发现异常模式。实施异常检测的方法有很多种,包括机器学习和统计分析。在本文中,我们将重点介绍统计方法,并介绍我们如何在 Booking 从头开始为时间序列数据构建自己的异常检测系统。

天真的方法

我在不同的公司和团队中看到的一个常见错误是,试图通过简单地将业务指标与一周前的值进行比较来检测异常。

按 Enter 键或单击以查看大图

img

本周与上周相比

乍一看,这种方法并非完全没有用——您可以发现一些异常,如上图所示。但这是一个可靠的长期解决方案吗?没有。最大的缺陷是今天的异常变成了下周的基线。这意味着,如果下周同一时间再次出现相同的问题,它可能会完全被忽视,因为我们现在正在与一个有缺陷的参考点进行比较

按 Enter 键或单击以查看大图

上周中断

上周中断

这看起来不对,我们简单的方法不知道上周的数据被泄露了。此方法的另一个限制是它一次只考虑一周。但是,如果性能在数周内逐渐下降怎么办?这种进展缓慢的问题很可能会从裂缝中溜走。

统计学

此时,我开始问自己:从头开始构建异常检测系统有多难我知道有很多机器学习解决方案可以解决这个问题,但简单的统计方法能完成这项工作吗?更重要的是——它足够好吗?让我们深入了解一下。

首先,让我们来看看最基本的统计测量之一:标准差

img

标准差

你以前可能见过这个钟形曲线,但标准差到底能如何帮助我们呢?关键思想是测量时间序列数据的波动。

例如,如果我们放大一个小时间窗口,例如过去 20 分钟,并将其与过去 4 周在同一时间的历史数据进行比较,我们可能会看到如下内容:

img

本周(绿色)与前几周(蓝色)

如您所见,这些指标的波动性很大,我们可以通过计算给定时期内的标准差来量化这种波动。为了使这更实用,让我们通过绘制一个图表来可视化数据,该图表包括平均值及其上方和下方的一个标准差。

img

随时间变化的标准差

如果我们进一步缩小并计算更大时间段内的标准差,我们可以观察到更广泛的变异性模式。

按 Enter 键或单击以查看大图

img

随时间变化的标准差(缩小)

有了平均值和标准差,我们现在可以构建 z 分数,这是一种强大的统计工具,用于识别异常值和检测数据中的异常。

什么是 Z 分数?

来自维基百科

在统计学中,标准分数或 z 分数是原始分数(即观察值或数据点)的值高于或低于正在观察或测量的平均值的标准差数。高于平均值的原始分数具有正标准分数,而低于平均值的原始分数具有负标准分数。

以下是计算 Z 分数的公式:

按 Enter 键或单击以查看大图

img

Z 分数公式

简而言之,Z 分数衡量特定数据点与平均值的距离。这对我们来说非常有用!事实上,它提供了一种检测时间序列数据中的异常或异常值的简单方法。这是我们第一种异常检测方法,以下是它的工作原理。

假设我们想要为以下指标构建一个异常检测系统:

按 Enter 键或单击以查看大图

img

本周

乍一看,很难说最后的下降是实际的异常还是只是正常行为。但是,让我们在同一张图表上绘制前几周的相同指标:

按 Enter 键或单击以查看大图

img

当前周(绿色)与前几周(蓝色)

现在,很明显有些事情不对劲了。那么我们如何将其转化为警报呢?这就是 Z 分数的用武之地。第一步是计算平均值。通常,我们会在特定时间窗口内执行此作,但为了简单起见,让我们计算除当前周之外的整个数据集。

按 Enter 键或单击以查看大图

img

多次前次 wek 的平均值

接下来,我们计算标准差:

按 Enter 键或单击以查看大图

img

前几周的标准差

一旦我们获得了历史指标的平均值和标准差,我们就可以计算当前指标中每个点的 Z 分数。

按 Enter 键或单击以查看大图

img

当前周指标的 Z 分数

注意到一个模式了吗?所有“异常”点的 Z 分数都低于 -3。这实际上是设置警报的一个很好的阈值。为了更好地理解 Z 分数值,我们可以参考 Z 分数表

按 Enter 键或单击以查看大图

img

Z 分数表

使用此表,我们可以查找每个 Z 分数代表什么。Z 分数为 -3 意味着只有 0.135% 的数据点低于该值,使其成为罕见事件。这使其成为异常阈值的有力候选者。

然而,我们很快意识到,仅依靠 Z 分数进行警报有其自身的缺点......

基于 Z 分数的警报的问题

我们在 Z 分数警报方面面临的最大挑战是我们的业务指标存储在 Graphite 中,这没有提供定义计算时间窗口的直接方法。最接近的可用函数是 movingAverage,但这不是很有帮助。如果我们尝试根据 4 周的数据计算标准差,我们最终得到这样的结果:

按 Enter 键或单击以查看大图

img

基于具有异常的历史指标的标准差

即使我们设法解决了推拉窗问题并过滤掉了过去的事件,仍然有其他问题需要处理。

当我们开始使用 Z 分数进行警报时,我们很快注意到夜间警报激增。原因?单个国家或大陆的业务指标在夜间自然会下降,因为用户不太活跃——他们正在睡觉!交易越少,偏差也越小,使 Z 分数更加不稳定,并且在低活动期间容易出现误报。

基于 Z 分数的警报的另一大缺点是它不是人类可读的。当警报基于抽象统计值时,很难估计事件的实际影响。想象一下,在半夜被这个警报吵醒:“过去 10 分钟内已处理订单的 Z 分数值较低 (-3.1)。

按 Enter 键或单击以查看大图

img

即使您检查仪表板,您可能仍然难以了解情况到底有多糟糕。更有用的警报是这样的:“我们在过去 10 分钟内丢失了 N 个订单。

这是可作的信息,您甚至不需要查看仪表板即可获得数字。

考虑到所有这些问题,我们意识到仅靠 Z 分数警报并不是正确的解决方案——我们需要找到更好的方法。

替代方法

鉴于基于 Z 分数的警报存在可读性问题,我们认为最好预测指标应该是什么,而不是仅仅通过统计方式标记异常。但是,由于许多业务指标波动很大,因此预测单个值并不理想。相反,我们决定建立一个范围——上限和下限——使我们能够考虑高度可变指标中的不确定性。

另一个挑战是,仅靠石墨不足以完成我们需要的计算。就在那时,我们决定开发一个小型服务,其唯一责任是计算预测范围并将其发送回 Graphite。这样,该服务就不会自行处理警报或异常检测——其他工具(如 Grafana)可以处理这个问题。我们的重点仍然是微调预测范围算法,而 Grafana 将处理检测和通知。

我们将此服务称为“Granomaly”,下面是异常检测系统工作原理的高级概述:

按 Enter 键或单击以查看大图

img

Granomaly 概述

Granomaly 的工作原理

Granomaly 服务的工作方式如下:

  1. 从 Graphite 读取历史数据(例如,特定指标的 4-5 周数据)。
  2. 过滤掉过去事件中的异常值。
  3. 计算预测范围(上限和下限)。
  4. 将范围作为两个单独的指标写回 Graphite。

实际的异常检测和警报发生在 Grafana 中,基于 Granomaly 生成的预测范围。由于 Grafana 在可视化这些指标时仍然需要做很多繁重的工作,因此我们意识到需要将仪表板作为代码进行管理——但本主题不在本文的讨论范围之内。

我们如何计算预测范围?

异常检测算法有很多,但我们想从简单的东西开始。我们的第一种方法是使用滑动窗口根据过去的数据确定上限和下限。

它的工作原理如下:

  • 对于每个新数据点,我们取一个时间窗口(例如 20 分钟)并查看过去 4-5 周内一周中同一天的历史值。
  • 然后,我们将第 N 个百分位数计算为下限,将第 (100-N) 个百分位数计算为上限。

例如,如果我们在 12:00 评估一个指标,我们会收集过去几周的 11:50 到 12:10 的值。如果我们选择 5 作为百分位参数,则我们将第 5 个百分位设置为预测范围的下限,将第 95 个百分位设置为预测范围的上限。

按 Enter 键或单击以查看大图

img

Granomaly 算法(动画)

我们在多个指标上测试了这种方法,效果出奇地好。通过调整百分位参数,我们甚至设法生成了一个平滑的预测范围,有效地解释了过去的异常情况,而不会让它们扭曲未来的预测。

然而,我们很快发现这种方法在重大中断或多个重叠事件的情况下表现不佳......

前几周指标中的重叠中断

虽然很少见,但我们偶尔会遇到一个问题,即由于。这是一个例子:

按 Enter 键或单击以查看大图

img

具有过去异常导致的伪影的谓词范围

如您所见,有两周该指标大约在同一时间出现了下降。在这些情况下,我们基于百分位数的方法很难生成可靠的预测范围。这清楚地表明,我们需要一种方法来调整历史数据中过去的事件。

但如何呢?

我们不想手动跟踪事件并排除它们——我们的目标是让 Granomaly 尽可能简单。相反,我们决定采用另一种统计方法:如果我们自动排除最偏差的数据点会怎样?

第一次尝试:排除最偏差的一周

我们最初的想法是删除导致与其他周偏差最大的一周。逻辑很简单:

  1. 以过去 N 周的数据为例。
  2. 生成 N-1 组合,每次不包括一周。
  3. 计算每个组合的标准差。
  4. 选择产生最小标准差的组合。

这种方法有效地过滤掉了大型异常,即使在发生严重事件的情况下也是如此。但有一个重大缺陷:

按 Enter 键或单击以查看大图

img

排除异常值后预测范围内的多个工件

那么发生了什么?此方法始终假设存在要排除的异常值,即使没有。这导致预测范围不稳定,使其在一般用途中不可靠。

显然,这不是正确的解决方案。所以我们重新开始,想出了更好的东西。

异常值排除

对于这种方法,我们决定使用一些统计技巧——我将用两个例子来解释。

在任何给定的时间间隔内,我们都会分析前几周同一时间和一周中的同一日期的数据点。假设我们正在查看以下数据集:

按 Enter 键或单击以查看大图

img

多周内一天同一时间的指标值

一眼就能发现异常值。该指标一直徘徊在 600 左右,但一周前突然降至 200。这看起来像是一个事件或异常,这意味着它不应该包含在我们的预测范围计算中。

第 1 步:计算 Z 分数

为了处理这个问题,我们首先计算这些值的标准差,然后确定每个数据点的绝对 z 分数:

按 Enter 键或单击以查看大图

img

每周 Z 分数

正如预期的那样,第 #1 周的 z 分数最高,使其成为一个明显的异常值。但是,我们没有简单地应用 z 分数截止值,而是采取了额外的步骤:

第 2 步:Z 分数归一化

这就是事情变得有趣的地方。我们不是根据固定的 z 分数阈值进行过滤,而是通过计算所有 z 分数值的中位数来执行 z 分数归一化:

按 Enter 键或单击以查看大图

img

Z 分数“归一化”

接下来,我们从中位数中减去每个 z 分数,并将归一化 z 分数保持在 0.6 阈值内的任何数据点。该阈值是根据经验选择的,但可以根据需要进行调整。

按 Enter 键或单击以查看大图

img

最后一步 — 检测异常值并将其从数据集中删除

这种所谓的 z 分数值“归一化”的目的是什么?为什么不简单地对原始 z 分数应用固定阈值呢?在上面的示例中,这种方法可能效果很好。然而,为了真正理解归一化的价值,让我们检查一下算法在没有明显异常的情况下如何执行。

没有明显异常值的案例

考虑以下数据集,其中不存在异常:

按 Enter 键或单击以查看大图

img

在多周内一天中的同一时间没有明显的异常值

乍一看,似乎没有什么不寻常的——这看起来像一个普通的数据集。理想情况下,在这种情况下,我们的方法不应排除任何数据点。

现在,让我们应用与之前相同的步骤。首先,我们计算绝对 z 分数:

按 Enter 键或单击以查看大图

img

每周 Z 分数

请注意,第 #1 周和第 #4 周具有最高值和最低值,这会导致较高的 z 分数。然而,从人类的角度来看,这些波动实际上并不是异常现象。这正是我们使用中位数对 z 分数进行归一化的原因。这是规范化后的样子:

按 Enter 键或单击以查看大图

img

每周“标准化”z 分数

在这里,没有一个数据点超过 0.6 阈值,这意味着没有点被过滤掉——这是正确的行为。

真实世界数据

那么这种方法在现实场景中如何支撑呢?下面是我们之前讨论的示例的预测范围的显示方式。

按 Enter 键或单击以查看大图

img

排除历史指标异常后的平滑预测范围

现在,让我们来看看另一个异常重叠的案例。

按 Enter 键或单击以查看大图

img

在历史指标中排除多个异常后的平滑预测范围

如您所见,即使异常发生在两个不同的周内,预测范围也保持平滑。现在我们已经消除了过去的异常,我们可以继续实时检测实际的异常。

检测异常

如前所述,Granomaly 服务不会直接检测异常,它只是生成预测范围指标。但是,一旦我们有了该指标,我们就可以使用任何可以访问它的工具轻松检测异常。

我们决定直接在 Grafana 中实施异常检测。这种方法为我们提供了一个快速的反馈循环,使我们能够快速试验不同的检测策略。下面是我们在团队中使用的异常检测仪表板的示例:

按 Enter 键或单击以查看大图

img

Grafana 中的异常检测仪表板

我们配置了仪表板和警报,以便每当某个值超出预测范围时,它就会被视为异常。对于每个指标,我们设置了两个警报:一个用于显着下降,另一个用于长时间内逐渐下降。这种方法使我们能够检测突然的中断和缓慢、逐渐的下降(我们通常称之为“缓慢燃烧”事件)。当然,每个指标的阈值都不同。为了简化 Grafana 中的配置并降低 Graphite 查询的复杂性,我们引入了“偏移量”指标,该指标在 Granomaly 服务中计算。

“偏移”指标

“偏移量”表示当前指标与预测范围之间的差异:

  • 如果当前值在范围内,则偏移量为 0。
  • 如果该值超过上限,则偏移量将计算为当前值与预测范围上限之间的差值。
  • 同样,如果该值低于下限,则偏移量计算为当前值与预测范围下限之间的差值。

按 Enter 键或单击以查看大图

img

偏移量度

这使得警报配置变得更加容易:

  • 只需将给定时间段内所有最新偏移值相加即可。
  • 将总和与阈值进行比较,以决定是否应触发警报。

更正事件

有一段时间,我们依赖异常检测,但很快又遇到了另一个挑战。当使用 Grafana 进行所有警报时,很难针对特定事件(例如假期、周末或超级碗或世界杯等重大事件)微调警报。我们知道某些业务指标在这些时期的行为有所不同,我们希望确保我们的期望得到适当调整。在 Grafana 的警报系统中配置所有这些并不是一件容易的事,因此我们采取了不同的方法。我们希望允许指定特定时间范围,并调整警报阈值或修改该时间段的预测范围指标。这就是我们提出“校正”指标的方式。

按 Enter 键或单击以查看大图

img

校正指标

校正指标的工作原理

校正指标非常灵活,并在 Granomaly 服务中配置:

  • 默认情况下,其值为 0,这意味着不应用任何更正。
  • 对于特殊事件,我们定义一个任意校正值(例如,10)。
  • 然后,该值被视为用于扩展预测范围的百分比调整。
  • “偏移”指标是根据调整后的预测范围计算的。

这种方法使我们能够预先为已知事件做好准备,确保高枕无忧,同时保持准确的异常检测。

检测异常下降,同时表现优异

我们遇到的另一个有趣的问题涉及业务指标中意外的超额表现。在此期间,我们的流量比预测多 15-20%,同时,一个小事件导致指标略有下降。

按 Enter 键或单击以查看大图

img

outperfoming 指标下降示例

如上图所示,此事件不会被注意到,因为该指标几乎没有触及预测范围的下限。从技术上讲,这可以被视为双重异常:

  1. 流量的整体增长本身就是一种反常现象。
  2. 在此期间的小幅下降是另一个异常现象,但由于流量高于预期,它被隐藏了。

我们本可以使用修正指标来解决这种情况,但由于这是一个意外情况,我们想要一种更灵活的方法。

介绍“调整系数”指标

为了更好地处理这个问题,我们决定在异常检测仪表板中引入一个额外的组件,称为“调整因子”。概念很简单:

  • 回顾过去几个小时的指标。
  • 确定一个调整因子,当乘以当前指标时,该因子会更好地定位在预测范围内。

按 Enter 键或单击以查看大图

img

调整后的指标

获得调整系数后,我们绘制了“调整后的原点”指标。然后,我们将警报系统配置为在原始指标或调整后的指标下降时触发。

这使我们能够检测到突然的下降,即使整体指标的表现远好于预期,确保我们不会因流量表现优异而错过异常情况。

模拟异常和中断

如您所见,上述异常检测过程中有许多组件,设置正确的值或调整异常值排除算法可能非常具有挑战性。每次发生事件时,我们都很高兴,因为它使我们能够测试我们的解决方案如何处理真实数据。但是,不幸的是,我们并不总是有幸处理实际事件。为了解决这个问题,我们想出了一种模拟方法。

这个想法是,在 Grafana 中设置异常检测仪表板并在 Granomaly 服务中对其进行配置之前,您可以首先测试它对所选指标的行为方式。

按 Enter 键或单击以查看大图

img

Granomaly 模拟界面

因此,我们在服务中构建了模拟页面,允许我们配置所有参数并测试它将为所选指标生成什么样的预测范围。此外,我们还添加了对各种指标异常的模拟,以测试异常值排除算法的效果。这非常有用,因为我们能够完善预测范围计算算法并在各种情况下对其进行测试,即使是那些在不同周内出现两个重叠异常的情况。任何人都可以简单地插入他们选择的指标并立即看到结果。反馈循环的大幅减少使得微调每个指标的预测范围变得更加容易,从而确保更准确的异常检测。

了解异常

所以,我们构建了所有这些,你可能会有一个问题:它有帮助吗?我们是否设法有效地检测到异常?事实证明,检测异常本身实际上并不难。真正的挑战是之后。

您会看到,当您处理系统中错误增加时,您通常可以将其追溯到故障组件。但是,如果您根本没有任何错误怎么办?如果您网站上的订单数量只是下降,并且您的系统没有任何变化或问题的迹象怎么办?一旦检测到这种异常,您将怎么做?

  • 只是天气好,还是你忘记了某种重大事件,而你的所有用户都处于离线状态?
  • 还是您的营销活动出现了一些问题?
  • 这可能是您的业务合作伙伴的问题,他们还不知道,但它已经影响了您?
  • 或者,也许正在进行的 A/B 测试破坏了一小部分用户的订单按钮的点击处理程序,他们根本无法提交表单?

任何事情都有可能发生。

你看,大多数时候,检测异常实际上并不难。弄清楚下一步该如何处理这些信息要棘手得多。有很大帮助的一件事是将您的业务指标分解为多个组件。不要只跟踪您网站上的订单,而是尝试按区域跟踪它们。或按设备,如 iPhone,Android,平板电脑,桌面浏览器等。或者通过营销渠道。实际上,这一点非常重要,因为您的公司以多种方式吸引用户,而且通常依赖于第三方服务。您希望确保不会因配置错误或另一端的问题而失去用户。

按 Enter 键或单击以查看大图

img

将单个指标分解为多个子指标

一旦您设法将核心重要指标分解为更小的组件,您就可以扩展异常检测仪表板以涵盖所有这些组件。这种方法将帮助您在处理数据中无法解释的行为时缩小范围。

结论

即使使用 z 分数、标准差、百分位数等基本统计工具,异常检测也可以非常有效。您无需成为机器学习专家即可为时间序列数据构建异常检测系统,但有几个关键挑战很突出:考虑过去的异常、通过模拟减少反馈循环以及理解检测到的异常。

如本文所示,统计方法可以成功识别异常值,但其有效性在很大程度上取决于历史数据质量。如果过去的异常扭曲了基线,预测就会受到影响,因此必须过滤掉它们——这是我们用我们的方法解决的挑战。

交互式模拟在将反馈循环从几天缩短到几秒钟方面发挥了至关重要的作用,允许对历史数据进行快速实验。这使得微调参数和评估给定指标是否适合异常检测变得更加容易。并非所有指标都足够可预测,无法使用这种方法,因此如果您正在构建异常检测系统,优化反馈循环至关重要。

然而,最具挑战性的方面是解释异常。指标突然严重下降通常很容易诊断,它通常伴随着其他警报,表明明显的系统故障。但是,如果您发现订单稳定下降 10%,没有错误、没有投诉、没有明显的技术问题怎么办?这可能是一个微妙的业务问题,营销活动的问题,甚至是像影响用户行为的天气模式变化这样简单的事情。这种不确定性使异常解释变得困难。按地区、设备或营销渠道细分指标可以帮助缩小原因范围,但这显然不是一个完整的解决方案。

最终,在分析异常之前,您需要先检测它——我希望本文已经表明,使用相对简单的统计技术是可能的。

Z分数
Z分数-归一化
“偏移”指标
“校正”指标
“调整系数”指标
这种异常检测方法仅适用于具有可重复的每周和每日模式的简单案例。它仍然缺乏的一件事是考虑趋势(例如,如果您的指标每周都在增长)。但是,如果您的指标在一个月内或多或少稳定,那么此模型效果很好。在 Booking,我们用相同的参数将其应用于许多不同的指标,到目前为止效果很好。我们甚至经常设法检测到缓慢下降(我们称之为“缓慢燃烧”)。不同指标的不同之处在于它们的波动性(标准差)。这会影响生成的预测范围。如果指标非常不稳定,则预测范围会变高。这没关系,我们可以简单地说,我们对此类指标的预测不太确定。当然,您可以增加此指标的百分位数,看看是否有帮助。


至于调整系数 - 无论原始指标如何,该技巧都适用于相同的参数。唯一要记住的是 - 它仅用于检测指标超出预期时的大幅下降。或者当指标表现不佳时会出现很大的颠簸。它不应用于检测小幅下降。

https://medium.com/booking-com-development/anomaly-detection-in-time-series-using-statistical-analysis-cc587b21d008