最近工作涉及有关异常检测的内容,而且前几天在公司做了一次有关异常检测算法和应用场景的分享,在此总结记录一下。
什么是异常检测?
异常检测(Anomaly Detection 或 Outlier Detection)指的是通过数据挖掘手段识别数据中的“异常点”,常见的应用场景包括:
金融领域:从金融数据中识别”欺诈案例“,如识别信用卡申请欺诈、虚假信贷等;
网络安全:从流量数据中找出”入侵者“,并识别新的网络入侵模式;
电商领域:从交易数据中识别”恶意买家“,如羊毛党、恶意刷屏团伙;
生态灾难预警:基于对风速、降雨量、气温等指标的预测,判断未来可能出现的极端天气;
工业界:可通过异常检测手段进行工业产品的瑕疵检测,代替人眼进行测量和判断。
除此之外,还有很多行业都在使用异常检测技术来帮助企业降低风险,并为业务提供指导建议。
异常点有哪几种类型?
目前比较公认的分类方式是分为三种:
-
单点异常(Global Outliers):也可以称为全局异常,即某个点与全局大多数点都不一样,那么这个点构成了单点异常。例如,和三只小黄人相比,海绵宝宝的混入就可以算作是单点异常。
→_→ 最右边这只看起来不太一样!
-
上下文异常(Contextual Outliers):这类异常多为时间序列数据中的异常,即某个时间点的表现与前后时间段内存在较大的差异,那么该异常为一个上下文异常点。例如,在某个温带城市夏天的气温时序数据中,其中有一天温度为10℃,而前后的气温都在25-35℃的范围,那么这一天的气温就可以说是一个上下文异常。
-
集体异常(Collective Outliers):这类异常是由多个对象组合构成的,即单独看某个个体可能并不存在异常,但这些个体同时出现,则构成了一种异常。集体异常可能存在多种组成方式,可能是由若干个单点组成的,也可能由几个序列组成。想象这样一个场景,某小区某天有一户人家搬家了,这是一件很正常的事,但如果同一天有10户同时搬家了,那就构成了集体异常,显然这不是一个正常小区会时常发生的事情。
在异常检测中经常遇到哪些困难?
1. 在大多数实际的场景中,数据本身是没有标签的,也存在一些数据集有标签,但标签的可信度非常低,导致放入模型后效果很差,这就导致我们无法直接使用一些成熟的有监督学习方法。
2. 常常存在噪音和异常点混杂在一起的情况,难以区分。
3. 在一些欺诈检测的场景中,多种诈骗数据都混在一起,很难区分不同类型的诈骗,因为我们也不了解每种诈骗的具体定义。
由于没有准确的标签,也没有对具体诈骗类型的理解,就导致我们陷入鸡生蛋 or 蛋生鸡的循环之中。要解决这种情况,目前比较常用的手段是,将无监督学习方法和专家经验相结合,基于无监督学习得到检测结果,并让领域专家基于检测结果给出反馈,以便于我们及时调整模型,反复进行迭代,最终得到一个越来越准确的模型。
到这里,我们都发现了,在风控场景中最重要的一环就是:专家经验。
异常检测算法的分类
异常检测涉及的场景非常丰富,那么异常检测算法可以从哪些角度进行分类呢?一般可以从以下四个角度作区分:
-
时序相关 VS 时序独立
-
全局检测 VS 局部检测
-
输出形式:标签 VS 异常分数
-
根据不同的模型特征
时序相关 VS 时序独立
首先可以根据该场景的异常是否与时间维度相关。在时序相关问题中,我们假设异常的发生与时间的变化相关,比如一个人平时的信用卡消费约为每月5000元,但11月的消费达到了10000元,那这种异常的出现就明显与时间维度相关,可能是因为”万恶“的双十一。
而在时序独立问题中,我们假设时间的变化对异常是否发生是无影响的,在后续的分析建模中,也就不会代入时间维度。
全局检测 VS 局部检测
在全局检测方法中,针对每个点进行检测时,是以其余全部点作为参考对象的,其基本假设是正常点的分布很集中,而异常点分布在离集中区域较远的地方。这类方法的缺点是,在针对每个点进行检测时,其他的异常点也在参考集内,这可能会导致结果可能存在一定偏差。
而局部检测方法仅以部分点组成的子集作为参考对象,基于的假设是,正常点中可能存在多种不同的模式,与这些模式均不同的少数点为异常点。该类方法在使用过程中的缺点是,参考子集的选取比较困难。
输出形式:标签 VS 异常分数
这种分类方式是根据模型的输出形式,即直接输出标签还是异常分数。输出标签的方法比较简单直观,可以直接根据模型输出的结果判断每个点是否为异常点。
使用可以输出异常得分的模型,我们可以进一步看哪些点的异常程度更高,也可以根据需要设定阈值,比如设定百分比,找出异常程度排在前10%的异常点。
根据不同的模型特征
最后,还可以根据模型本身的特点进行分类,大致可以分为以下几种:
-
统计检验方法
-
基于深度的方法
-
基于偏差的方法
-
基于距离的方法
-
基于密度的方法
-
深度学习方法
如今用于异常检测的算法已经非常多了,但万变不离其宗,无论优化到什么程度,它们都是由一些原始的模型和思想衍生出来的。下面来回顾一下这些最原始的模型思想。
异常检测经典模型思想
统计检验方法
使用这类方法基于的基本假设是,正常的数据是遵循特定分布形式的,并且占了很大比例,而异常点的位置和正常点相比存在比较大的偏移。
比如高斯分布,在平均值加减3倍标准差以外的部分仅占了0.2%左右的比例,一般我们把这部分数据就标记为异常数据。
高斯分布
使用这种方法存在的问题是,均值和方差本身都对异常值很敏感,因此如果数据本身不具备正态性,就不适合使用这种检测方法。
基于深度的方法
基于深度的方法,即从点空间的边缘定位异常点,按照不同程度的需求,决定层数及异常点的个数。如下图所示,圆中密密麻麻的黑点代表一个个数据点,基于的假设是点空间中心这些分布比较集中、密度较高的点都是正常点,而异常点都位于外层,即分布比较稀疏的地方。
如下图,最外层点的深度为1,再往内几层深度一次为2、3、4…… 若我们设置阈值k=2,那么深度小于等于2的点就全部为异常点。这一方法最早由 Tukey 在1997年首次提出。
但这个基础模型仅适用于二维、三维空间。现在有很多流行的算法都借鉴了这种模型的思想,但通过改变计算深度的方式,已经可以实现高维空间的异常检测,如孤立森林算法。
基于偏差的方法
这是一种比较简单的统计方法,最初是为单维异常检测设计的。给定一个数据集后,对每个点进行检测,如果一个点自身的值与整个集合的指标存在过大的偏差,则该点为异常点。
具体的实现方法是,定义一个指标 SF(Smooth Factor),这个指标的含义就是当把某个点从集合剔除后方差所降低的差值,我们通过设定一个阈值,与这些偏差值进行比较来确定哪些点存在异常。这个方法是由 Arning 在1996年首次提出的。
基于距离的方法
基于距离的方法,即计算每个点与周围点的距离,来判断一个点是不是存在异常。基于的假设是正常点的周围存在很多个近邻点,而异常点距离周围点的距离都比较远。
有一个比较古老的DB基础模型,是1997年被首次提出的,基本思想是:我们给定一个半径 ε 和比例 π,假设对点 p 进行异常检测,若与 p 点的距离小于半径 ε 的点在所有点中的占比低于 π,则点 p 为异常点。比如下图中的 p1 和 p2 两个点,它们方圆 ε 的范围内没有点,就会被模型标记异常。
之后基于最初这个模型,又出现了基于嵌套循环、基于网格的距离模型,再之后就是我们熟知的 kNN、KMeans,都可以通过计算距离来做异常检测。
基于密度的方法
与基于距离的方法类似,该类方法是针对所研究的点,计算它的周围密度和其临近点的周围密度,基于这两个密度值计算出相对密度,作为异常分数。即相对密度越大,异常程度越高。基于的假设是,正常点与其近邻点的密度是相近的,而异常点的密度和周围的点存在较大差异。
设计这种方法的动机是,基于距离的异常检测方法不能很好地处理一些密度存在差异的数据集。如下图中的数据点分布,如果使用基于距离的模型,半径和比例已经设定好了,点 o2 很容易被识别为异常点,因为右上的 C1 子集中很多点与周围点的距离要比 o2 还小,其中很多点就会被标为正常点。但如果从密度的角度来看,o2 更像是一个正常点。所以无论单从哪个角度看,我们都可能会忽略另一个维度上的特征,因此还是要根据具体场景和目标任务,以及数据集本身的特点来进行算法的选择,或是进行算法的结合。
深度学习方法
目前最常用于异常检测的深度学习方法要非 Autoencoder 莫属了。
Autoencoder 的中文名叫自编码器,由 Encoder(编码器)和 Decoder(解码器)两部分构成,如下图:
Autoencoder 的结构
左边部分为编码器,它可以把高维的输入压缩成低维的形式来表示,在此过程中,神经网络会尽量留下有用的信息,去除掉一些不重要的信息和噪声。右边部分为解码器,它负责把压缩了的数据再进行还原,努力恢复成原本的样子。也就是说,训练的时候是这个样子的:
whatever = autoencoder.fit(X_train, X_train, ...)
妥妥的自己训练自己,是一个自力更生的模型!
那么为什么它压缩自己再解压,这样折腾一圈后就能用来检测异常呢?这里借用李宏毅老师课程中的例子作解释:
在训练过程中,我们用辛普森一家中的人物丽莎作为训练数据,来训练一个 Autoencoder 模型,让模型对图像进行压缩再还原,训练好后,模型记住了如何进行这种图像的编码和解码。
此时,使用辛普森家人中爷爷的图像进行这个模型的测试,此时模型有很好的还原表现,因为丽莎和爷爷很像,模型之前已经知道如何处理这种数据了。
但是,如果用凉宫春日的头做测试……
结果就很糟糕了,因为模型不认识长这样子的人。因此,Autoencoder 能够记住自己见过的数据,如果来了新的、相似的数据,也能进行比较好的还原。但如果来了不同于以往的数据,则会有非常大的还原误差。基于这一点,我们可以使用 Autoencoder 做很多场景的异常或欺诈检测。
⬇️ 扫描下方二维码关注公众号【数据池塘】 ⬇️
回复【算法】,获取最全面的机器学习算法网络图: