我应该使用什么算法来检测时间序列的异常?


69

背景

我在网络运营中心工作,我们监视计算机系统及其性能。要监视的关键指标之一是当前连接到我们服务器的访问者/客户数量。为了使其可见,我们(Ops团队)收集了诸如时间序列数据之类的指标并绘制了图表。Graphite允许我们做到这一点,它有一个非常丰富的API,我可以用它来构建警报系统,以便在突然(主要是)突然下降和其他更改发生时通知我们的团队。目前,我已基于avg值设置了一个静态阈值,但是由于白天和一周中的不同负载(季节性因素),它不能很好地工作(存在很多假阳性)。

看起来像这样: 每个系统的用户数

实际数据(一个度量标准的示例,时间范围为15分钟;第一个数字是用户数,第二个-时间戳):

[{"target": "metric_name", "datapoints": [[175562.0, 1431803460], [176125.0, 1431803520], [176125.0, 1431803580], [175710.0, 1431803640], [175710.0, 1431803700], [175733.0, 1431803760], [175733.0, 1431803820], [175839.0, 1431803880], [175839.0, 1431803940], [175245.0, 1431804000], [175217.0, 1431804060], [175629.0, 1431804120], [175104.0, 1431804180], [175104.0, 1431804240], [175505.0, 1431804300]]}]

我要完成的工作

我创建了一个Python脚本,该脚本接收最近的数据点,将它们与历史平均值进行比较,并在发生突然变化或下降时发出警报。由于季节性因素,“静态”阈值无法正常运行,脚本会生成误报警报。我想提高警报算法的准确性,使其在不不断调整警报阈值的情况下工作。

我需要什么建议和发现的东西

通过谷歌搜索,我发现我正在寻找用于异常检测的机器学习算法(无监督算法)。进一步的调查表明,其中有很多,很难理解哪种情况适用于我的情况。由于我的数学知识有限,我无法阅读复杂的学者论文,并且正在寻找对该领域的初学者来说简单的东西。

我喜欢Python并且对R有点熟悉,因此很高兴看到这些语言的示例。请推荐一本好书或文章,这将有助于我解决问题。谢谢您的时间,请原谅我这么长时间的描述

有用的链接

类似问题:

外部资源:


1
您是否看过像CUSUM这样最简单的算法之一?
Vladislavs Dovgalecs,2015年

@xeon,还没有。我是这个主题的新手,需要一些时间来消化所有内容。感谢您提出来,这是一个很好的起点,我现在就可以实施
Ilya Khadykin 2015年

1
这是个好问题,@ ma-ge。我有类似的情况。我的方法是使用auto.arimaR的出色forecast软件包提供的功能通过建立连续的定期预测来设置警报(请参阅jstatsoft.org/v27/i03/paper)。您可以通过调整level参数来调整置信度,例如data.model <- auto.arima(data.zoo, ic = c("bic")); data.prediction.warningLimits <- forecast(data.model, h=1, level=0.99)
Alex Woolford

3
Twitter的家伙们就这个话题写了非常有趣的文章。看看:blog.twitter.com/2015/…–
ognjenz

嘿@IlyaKhadykin希望您一切都好!你有没有解决这个问题的办法?我所做的事情完全相同,每分钟我们都有特定的用户,而且我们还会得到很多误报。截至目前,我们正在每隔5分钟计算一次间隔数据的得分,并将其与历史模式进行匹配。如果您有任何特殊的算法工作,可以请您分享一下。提前致谢!
ak3191

Answers:


23

我认为关键是图表中的“意外”限定符。为了发现意外情况,您需要对预期有一个了解。

我将从一个简单的时间序列模型开始,例如AR(p)或ARMA(p,q)。使它适合数据,并适当添加季节性。例如,您的SAR(1)(24)模型可以是:,其中是以小时为单位的时间。因此,您将在接下来的一个小时内预测图表。每当预测错误 “太大”时,您就会发出警报。yt=c+ϕyt1+Φ24yt24+Φ25yt25+εttet=yty^t

估算模型时,您将获得误差的方差。根据分布假设(例如正态分布),可以基于概率设置阈值,例如表示99.7%或单面。σεεt|et|<3σεet>3σε

参观者的数量可能是相当固定的,但是是季节性的。尝试使用季节性虚拟变量而不是乘法季节性变量可能会更好,然后尝试使用ARMAX,其中X代表外生变量,例如假人,小时虚拟变量,周末虚拟变量等。


5
该方法假定一个特定的ARIMA模型,该模型将基于隐式假定为不存在的异常而具有偏差参数。一个更通用的方法是先确定异常,然后再找到导致在线显着性检验的最佳ARIMA模型。另外,异常可能是电平移动,季节性脉冲和本地时间趋势,这需要比此处提出的解决方案更为通用的解决方案。请参阅 unc.edu/~jbhill/tsay.pdf 了解完整的程序。您也可以通过Google“自动干预检测”了解更多信息。
IrishStat

@IrishStat我建议ARIMAX带有虚拟事件。OP可以解决已知事件,例如网站因虚拟人损毁。这将减少误差差异,并且会有更多警报。没有理由建立复杂的模型,因为在涉及网站流量时根本无法考虑所有内容。简单模型将最有效。
阿克萨卡(Aksakal)

2
@ ma-ge,还有一件事:您可能想使用重叠的间隔。假设您每分钟收集一次数据,但是对于建模,您可以在10分钟内选择一个步骤。它会产生一些估计问题(由于自相关),但是生成的模型很可能会更健壮。
阿克萨卡(Aksakal)

@Aksakal模型应该尽可能简单,但不要太简单。
IrishStat

17

在Netflix技术博客上,有一篇有关其鲁棒异常检测工具(RAD)的文章。 http://techblog.netflix.com/2015/02/rad-outlier-detection-on-big-data.html

它处理季节性和非常大的数据集,因此可能符合您的要求。该代码是开源Java和Apache Pig https://github.com/Netflix/Surus/blob/master/resources/examples/pig/rad.pig

底层算法基于强大的PCA-参见此处的原始文章:http : //statweb.stanford.edu/~candes/papers/RobustPCA.pdf


12

开源软件包中的大多数离群值检测算法用于包含低频,每日/每周/每月频率数据的业务时间序列数据。此数据似乎是针对在几分钟内捕获的特定区域的,因此我不确定开源离群值检测是否会有所帮助。您可以尝试使这种方法适应您的数据。

下面,我概述了一些可用的开源软件包方法R

  1. tsoutliers:在arima框架内实现Chen和Liu的异常检测算法。请参阅我在此站点上的先前问题。很棒的方法,但是非常慢,不确定它是否能够像您一样处理高频数据。正如我前面的问题/帖子中提到的那样,它具有检测所有类型异常值的优势。
  2. Twitter的异常检测:使用Rosner算法根据时间序列检测异常。该算法分解时间序列,然后检测异常。我个人认为,这在检测时间序列中的异常时效率不高且不准确。
  3. 预测包中的tsoutlier:在分解时间序列然后检测异常值方面类似于twitter的算法。仅将检测附加的离群值或脉冲。

有一些商业软件包具有专用的方法来尝试和检测异常。另一个经典方法是Tsay的时间序列离群值检测算法,类似于Chen和Liu的方法,它检测不同类型的离群值。最近,我还偶然发现了这种名为metafor的商业软件解决方案,该解决方案可能更适合您的数据。

希望这会有所帮助


谢谢,它给了我关于类似问题和方法的观点;特别感谢您的链接!
伊利亚·哈迪金

如果有人在寻找Metafor,我们就会被Splunk收购。我们的TSAD算法包含在最新版本的Splunk IT Service Intelligence(“ ITSI”)中。
亚历克斯·克鲁斯

4

您是否尝试过使用统计过程控制规则(例如Western Electric http://en.wikipedia.org/wiki/Western_Electric_rules)?

我将它们用于时间序列数据(通常带有一些数据直觉),以评估数据是否在我不希望去的地方。像您的示例一样,这些规则说明如果增量/更改在多个数据点上是一致的,则表示可能存在问题。

如果您的状况比以前好或坏,那么统计过程控制(SPC)也可以很好地解决问题。

SPC的一个问题是,它大部分依赖于正态分布,该正态分布可能不适合您的数据,该数据不能低于零。其他比我更好的使用SPC的人可以在这里建议选择。我喜欢用它来标记问题,但像所有模型一样,最好将其与有关数据本身(和源)的知识一起使用。


4

其他的答案似乎没有提到,您的问题听起来像是一个变更点检测。changapoint检测的想法是,您正在数据中寻找在术语属性(例如,均值,方差)方面存在显着差异的细分。这可以通过使用最大似然估计来实现,其中对于变化点,似然函数为m

L(m,τ1:m,θ1:(m+1))=i=1m+1p(y(τi1+1):τiθi)

其中是您的数据,是标记变化的边界点,概率分布由每个第个分段的参数化。这可以很容易地推广到各种情况。存在许多找到参数的算法,包括找到未知的。也有可用的软件来估算此类模型,例如R的软件包。如果您想了解更多,可以查看以下出版物及其提供的参考: 1 < τ 1 < < τ < Ñ p θ 中号y1,,yn1<τ1<<τm<npθiimchangepoint

丽贝卡·基里克(Rebecca Killick)和伊德里斯·A·埃克莱(Idris A. Eckley)。(2013)变更点:用于变更点分析的R包。(在线纸)

IA的Eckley,Fearnhead的P.和Killick的R.(2011年)变更点模型分析。[in:] 贝叶斯时间序列模型,eds。D. Barber,AT Cemgil和S. Chiappa,剑桥大学出版社。


4

鉴于应该很好地理解时间序列的周期性,可以设计出一种简单但有效的基于差分的算法。

一个简单的一步差分即可检测到先前值的突然下降

yt=ytyt1

但是,如果该系列的周期性成分很强,那么您希望定期下降的幅度会很大。在这种情况下,最好将上一个周期(即一个周期前)的同一点的任何值与其对应值进行比较。

yt=ytytnwhere n=length of period

对于发布的问题,自然会期望两个重要的周期性成分,一个是一天的长度,另一个是一周的长度。但这并不是什么复杂的事情,因为较长时间段的长度可以巧妙地除以较短时间段的长度。

如果每小时进行一次采样,则上式中的应设置为24 * 7 = 168n247=168

如果跌落更多是成比例的,那么当活动度较低时,简单的差异将很容易检测不到突然的跌落。在这种情况下,可以修改算法以计算比率。

yt=ytytn

我使用模拟数据集在R中做了一些测试。其中每天要采样6次数据,并且每天和每周都有很强的周期,以及其他噪声和波动。
将液滴添加到任意位置,持续时间介于1到3之间。要分离液滴,首先要计算距离42,然后将阈值设置为0.6,因为只有特定大小的负变化才有意义。然后计算一个单步差,并将阈值设置为-0.5。最后,似乎漏掉了一个误报(第16周末的误报)。左图和右图以不同的方式显示相同的数据。

在此处输入图片说明


3

将时间序列中的变化视为新趋势的开始而不是异常现象会更有用吗?取相邻点之间的差值将有助于判断斜率(导数)何时变化,并且可能标志着日期中新趋势的开始。也可以使用差值的差(二阶导数)。用Google搜索“趋势的时间序列开始”可能会为方法提供很好的建议。在财务数据中,新趋势(您是买还是卖?)引起了人们的关注,因此有关于此主题的论文。

小波的一个很好的介绍是我相信作者是哈伯德的《小波的世界》。


2

使用两种不同的算法,我可以在多个季节的时间序列(每天,每周)中获得一些不错的结果:

  • 使用黄土(或STL)建立中点序列的季节性趋势分解
  • 基于方差和水平之间的关系的非线性回归以在该中点附近建立阈值。

STL将时间序列的时域分解为趋势成分,单个季节成分和其余部分。季节性成分是您的高频季节性(例如每天),而趋势既包括低频季节性(例如每周)又包括适当的趋势。您可以通过仅在趋势图中再次运行STL来将两者分开。无论如何,一旦将其余系列与其他组件隔离开,就可以对该系列执行异常检测。

我在这里做了更详细的文章:

https://techblog.expedia.com/2016/07/28/applying-data-science-to-monitoring/


1

受到David的启发,您是否尝试过使用FFT?它可能能够发现突然下降的情况,因为那些突然下降表明您的异常情况。异常可能出现在狭窄的范围内。这样您就可以轻松捕获它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.