可解释的异常值检测:计数异常值检测器

2024年06月20日 由 alex 发表 115 0

本文将介绍一种可解释的异常值检测方法--计数异常值检测器。


记录成为异常值的原因与了解哪些记录是异常值同样重要。事实上,如果我们无法确定被标记为异常值的记录的原因,那么进行异常值检测的价值往往是有限的。例如,如果异常值检测系统发现了可能存在安全威胁的记录,要想有效地进行调查,就必须知道异常的原因:为什么会被识别为异常。同样,如果异常值检测系统识别出可能的欺诈、机器故障、科学发现、异常有效(或无效)的商业行为或其它异常值,也需要知道异常点是什么。


虽然检测器所采用的算法本身通常很容易理解,但单个预测通常却不容易理解。例如,隔离林 (IF)、局部异常因子 (LOF) 和 kth Nearest Neighbors (kNN) 等标准检测器的算法简单易懂,但产生的分数可能难以评估,尤其是在高维数据中。很难确定被标记为异常值的记录为何异常。


原则上,解释异常值是很容易的。对于大多数异常值,只有一小部分特征具有异常值(极少数异常值的每个特征都具有异常值)。要了解异常值为何是异常值,通常只需知道哪些特征异常以及这些特征如何异常即可,但遗憾的是,我们通常无法做到这一点。


只有少数异常值检测器会对其产生的分数做出解释。其中包括 FPOF 和基于关联规则的相关异常值检测方法,这里仅举两个例子。但是,可解释的模型比我们希望的要少得多。受此启发,我开发了两个可解释的模型:计数异常值检测器(COD)和数据一致性检查器(Data Consistency Checker)。


它们的工作原理有很大不同,但都是有用的工具。


计数器异常值检测器

计数异常值检测器 (COD) 是一种针对表格数据的异常值检测器,旨在对标记为异常值的行及其具体分数提供清晰的解释。更具体地说,COD 是一种基于多变量直方图的模型:它将数据划分为若干个箱,并将箱中计数异常低的记录识别为异常值。


这是一种有效、高效、可解释的异常值检测技术。多维直方图有一些非常实际的局限性,我们将在这里进行介绍,但正如我们将要介绍的,这些局限性是完全可以解决的。对该方法的测试和评估发现,它是一种强大的检测器,通常与更标准的工具一样有用,而且具有可解释性的巨大优势。


基于直方图的异常值检测简介

在介绍 COD 之前,我将先介绍另一种更简单的基于直方图的异常值检测算法,它比 COD 更早出现,名为 HBOS(基于直方图的异常值得分)。它是流行的 PyOD(Python 异常值检测)库的一部分,本身通常也是一种有效的工具。其他基于直方图的异常值检测算法也有类似的功能。


HBOS 的工作原理非常简单:要确定表格中某一行的异常程度,只需评估该行中每个值的异常程度即可。为此,需要将每个值与其列进行比较。具体做法是,首先创建一个直方图来表示每个特征(HBOS 严格使用数值数据),然后将每个值与直方图进行比较。


还有其他方法可以确定数值相对于表列(或其他数值序列)的异常程度。核密度估计、累积分布和其他方法也可以很好地发挥作用。但直方图是一种直接有效的方法。


HBOS 将每个特征划分为一组等宽的箱。然后,每个特征都可以用直方图来表示,例如:


7


在本例中,直方图使用了 20 个分区;对于 HBOS,我们通常会为每个特征使用 5 到 50 个分区。如果表格中有 30 个特征,那么就会有 30 个这样的直方图。


任何数值如果位于计数极低的细分区,都会被认为是不寻常的。例如,在这个直方图中,6.0 左右的值会被认为是罕见的,因为它所在的小区间在训练数据中只有很少的示例;它会被赋予一个相对较高的异常值。而 4.0 的值则被认为非常正常,因此异常值得分较低。


因此,在评估一行数据时,HBOS 会确定该行中每个值的不寻常程度(相对于其特征的直方图而言),给每个值打分,然后将这些分数相加。这样,具有最罕见值和最稀有值的行将获得最高的异常值总分;如果某一行的单个值在其列中极为罕见,或者某一行的多个值在其列中属于中度罕见,那么该行就可能获得较高的异常值总分。


这意味着 HBOS 只能发现一种特定类型的异常值:包含一个或多个异常单值的行;而不能识别包含异常值组合的行。这是一个非常大的限制,但 HBOS 的工作速度非常快,而且它识别出的异常值往往是真正的强异常值,即使它也会漏掉很多异常值。


尽管如此,HBOS 仍然会漏掉一些不寻常的值组合,这是一个很大的局限性。例如,在一个描述人的表格中,一条记录的年龄可能是 130 岁,身高可能是 7'2",HBOS 会检测到这些值。但是,一条记录的年龄可能是 2 岁,身高可能是 5'10"。年龄和身高可能都很常见,但组合却不常见:这是两个特征罕见组合的一个例子。


也有可能出现三个、四个或更多特征的罕见组合,这些组合可能与不寻常的单一值一样相关。


计数异常值检测器概述

COD 扩展了基于直方图的异常值检测理念,并支持多维直方图。这使得 COD 可以识别由 2、3 或更多值组成的罕见组合异常值,以及 HBOS 等基于标准(1d)直方图的方法可以检测到的罕见单一值。它可以捕捉到不寻常的单一值,如身高 7'2" ,也可以捕捉到一个人的年龄为 2 岁,身高为 5'10"。


我们先看 2 维直方图,但 COD 支持多达 6 维的直方图(我们将在下文说明为什么不超过 6 维,事实上,只使用 2、3 或 4 维通常效果最好)。


二维直方图也可以看成热图。在下图中,我们可以看到二维空间中的直方图,其中每个维度的数据被分为 13 个小区间,在二维空间中形成了 169 (13 x 13) 个小区间。我们还可以看到一个点(画圈处)是二维空间中的异常点。这个点所在的分区只有很少的项目(在本例中只有一个项目),因此在检查这个二维空间时可以将其识别为异常点。


8


这个点在 1d 空间中都不是异常点;它在 x 维度或 y 维度中都没有异常,因此会被 HBOS 和其他每次只检查单一维度的工具忽略。


与 HBOS 一样,COD 也会为每个单一特征创建一个 1d 直方图。不过,COD 也会为每对特征创建类似的 2d 直方图,因此能够检测到任何不寻常的值对。同样的想法也可以应用于任何维度。虽然绘制起来比较困难,但 COD 可以为每三重特征创建三维直方图(每个分隔点都是一个立方体),以此类推。同样,它(利用训练数据)计算每个仓中的计数,并能识别异常值:出现在异常低计数仓中的值(或值的组合)。


维度的诅咒

虽然基于每组 2 个、3 个甚至更多特征创建直方图很有效,但使用所有特征创建直方图通常是不可行的,至少当数据中的特征超过 6 或 7 个时是如此。由于所谓的 "维度诅咒"(curse of dimensionality),我们可能拥有比数据记录多得多的分区。


例如,如果有 50 个特征,即使每个特征只使用 2 个分区,在 50d 直方图中也会有 50 个分区的 2 次方,这肯定比数据记录的数量大很多个数量级。即使只有 20 个特征(每个特征使用 2 个仓),我们也会有 20 的 2 次方,超过 100 万个仓。因此,我们最终会发现大多数分仓都没有记录,而有记录的分仓也只包含一两个项目。


大多数数据都相对偏斜,而且特征之间通常存在关联,因此这种影响不会像数据在空间中均匀分布那样强烈,但使用基于直方图的异常值检测方法,仍然可能有太多特征需要同时考虑。


不过幸运的是,这实际上并不是一个问题。无需创建高维直方图;低维直方图就足以检测出最相关(和最可解释)的异常值。例如,检查每个 1d、2d 和 3d 空间就足以找出每个不寻常的单一值、值对和值三重。这些都是最容易理解的异常值,也可以说是最相关的(或至少是最典型的相关值)。如果需要(并且有足够的数据),也可以使用 COD 检查 4d、5d 或 6d 空间。


COD 算法

COD 算法首先检查 1d 空间,然后是 2d 空间,接着是 3d,以此类推,最多检查 6d。如果一个表有 50 个特征,这将检查(50 选 1)个 1d 空间(找出不寻常的单个值),然后是(50 选 2)个 2d 空间(找出不寻常的值对),然后是(50 选 3)个 3d 空间(找出不寻常的值三),以此类推。这涵盖了大量空间,但这意味着每条记录都会被彻底检查,而且不会遗漏异常情况(至少在较低维度上)。


使用直方图还可以实现相对较快的计算速度,因此一般来说比较容易操作。在特征数量非常多的情况下,这种方法可能会失效,但在这种情况下,几乎所有异常值检测器最终都会失效。当一个表有很多特征时(例如,几十个或几百个),可能有必要将 COD 限制在 1d 空间内,只找出不寻常的单个值--在任何情况下,这对这种情况都是足够的。但对于大多数表格来说,COD 甚至可以很好地检查多达 4、5 或 6d 的空间。


使用直方图还可以消除许多异常值检测方法(包括一些最常用的方法)所使用的距离度量。虽然 LOF、kNN 等方法在低维度下非常有效,但在高维度下,这些方法会一次性使用所有特征,极易受到维度诅咒的影响。例如,kNN 将异常值识别为与其 k 个近邻相对较远的点。这是一种合理且普遍有效的方法,但在维度非常高的情况下,点与点之间的距离计算会变得非常不可靠,从而导致无法使用 kNN 或类似算法识别异常值。


COD 每次只检测较小的维度,因此能够处理的特征远多于许多其他异常值检测方法。


将评估局限于小维度

要想知道为什么只需检测 3 到 6 个维度就足够了,我们来看看 4d 异常值的例子。我所说的 4d 异常值是指四个特征的罕见组合,而不是任何 1、2 或 3 个特征的罕见组合。也就是说,每个单一特征、每对特征和每个三重特征都相当常见,但所有四个特征的组合却很罕见。


这种情况有可能发生,也确实存在,但实际上并不常见。对于大多数具有罕见的 4 个特征组合的记录来说,其中至少有两个或三个特征的子集通常也是罕见的。


在开发这个工具和其他工具的过程中,我发现了一个有趣的现象,那就是大多数异常值都可以根据一组相对较小的特征来描述。例如,考虑一张表示房价的表格(有四个特征),我们可能有以下特征:平方英尺、房间数、楼层数和价格。任何一个不寻常的值都可能是有趣的。同样,任何一对特征值(例如,低平方英尺,高楼层数;或低平方英尺,高价格),以及任何三重特征值都可能很有趣。但是,在不存在任何不寻常的单一值、不寻常的一对或不寻常的三重特征的情况下,所有四个特征组合的不寻常程度是有限的。


通过只检查较低维度,我们就能覆盖大部分异常值。涵盖的维度越多,我们发现的异常值也就越多,但无论是在异常值的数量上,还是在其相关性上,都会出现收益递减的情况。


即使存在一些只能用六或七个特征描述的合法异常值,它们也很可能难以解释,其重要性也可能低于只有一个稀有值、一对稀有值或三对稀有值的异常值。此外,由于在使用少量特征时,值的组合数量可能会非常大,因此也很难对它们进行统计量化。


通过处理少量特征,COD 在独立考虑每个特征的检测器(如 HBOS、z-score、四分位间范围、基于熵的测试等)和一次性考虑所有特征的异常值检测器(如局部异常因子和 KNN)之间提供了一个很好的中间地带。


COD如何消除解释中的冗余

计数异常值检测器的工作原理是,首先单独检查每一列,找出相对于其列而言不寻常的所有值(1d 异常值)。


然后,检测器会检查每一对列,找出每一对列中具有成对异常值的行列(2d 异常值)。然后,检测器会考虑 3 列的集合(识别 3d 异常值)、4 列的集合(识别 4d 异常值),以此类推。


在每个阶段,算法都会寻找不寻常的实例,排除低维空间中已经标记的值或组合。例如,在上述人物表中,身高为 7'2" 的人很少见。因此,任何年龄和身高(或身高和其他)的组合,只要身高是 7'2" 都是罕见的,因为 7'2" 是罕见的。因此,没有必要把身高 7'2" 和年龄 25 这样的组合确定为罕见组合;它之所以罕见,只是因为 7'2" 罕见,把它作为 2d 异常值报告是多余的。严格来说,将其报告为 1d 异常值(仅基于身高)可以为包含该身高的任何行提供最清晰、最简单的解释。


因此,一旦我们将 7'2" 确定为 1d 异常值,我们在检查 2d 异常值、3d 异常值等时就不会再包含这个值。不过,大部分值(相对于当前数据集而言较为典型的身高)会被保留下来,这样我们就可以进一步检查数据,找出不寻常的组合。


同样,二维空间中任何罕见的成对数值都会被排除在三维和更高维度空间的考虑范围之外;三维空间中任何罕见的三对数值都会被排除在四维和更高维度空间的考虑范围之外;以此类推。


因此,报告每种异常情况时都会使用尽可能少的特征,从而使对每种异常情况的解释尽可能简单。


不过,任何一行都可能被标记多次。例如,某行的 F 列可能有一个异常值;A 列和 E 列可能有一对异常值;D 列和 F 列可能有另一对异常值;B 列、C 列和 D 列可能有三组异常值。


可解释性

我们可以为数据集中的每个异常值确定其异常的特定特征集。这样,我们就可以对其做出非常清晰的解释。而且,鉴于很大一部分异常值都是 1d 或 2d 空间中的异常值,大多数解释都可以直观地呈现出来(示例如下)。


评分

计数异常值检测器之所以叫计数异常值检测器,是因为它检测的是每个分区的精确计数。在每个空间中,异常低计数(如果有的话)的分区会被识别出来,任何数值在这些分区中的记录都会被识别为异常值。


随后使用的评分系统非常简单,这进一步支持了可解释性。每个罕见值或罕见组合的评分都是相同的,与维度或箱内计数无关。每一行只是根据发现的异常值的数量进行评分。


这可能会降低一些保真度(罕见组合与非常罕见组合的得分相同),但执行时间明显更快,结果也更容易解释。这也避免了对不同空间的异常值进行加权的复杂性和任意性。例如,如何比较 4d 空间和 2d 空间中的异常值可能并不清楚。COD 消除了这一问题,对每个异常值一视同仁。因此,这确实会牺牲一些评分细节来换取可解释性,但该工具的重点是可解释性,而且对准确性的影响很小(正负影响都有--同等对待异常值会产生正则化效应)。


默认情况下,只有强烈异常的值或组合才会被标记。可以通过设置阈值参数来调整这一过程。


示例

在此,我们提供一个使用 COD 的简单示例,使用 scikit-learn 提供的玩具数据集--虹膜数据集。要执行该示例,首先必须导入 CountsOutlierDetector 类。然后,我们只需创建一个 CountsOutlierDetector 实例,并调用 fit_predict()。


import pandas as pd
from sklearn.datasets import load_iris
from counts_outlier_detector import CountsOutlierDetector
iris = load_iris()
X, y = iris.data, iris.target
det = CountsOutlierDetector()
results = det.fit_predict(X)


结果包括通过数据集中每一行的得分、标记行的原因以及数据集异常值的整体汇总统计信息。


可视化说明

COD 提供了多种方法来帮助理解所发现的异常值。首先是 explain_row() 应用程序接口,用户可以通过该程序接口了解指定行得分背后的原因。


如前所述,异常值行可以有任意数量的异常。对于发现的任何单维度异常,都会显示条形图或直方图,将该值与列中的其他值联系起来。为了进一步了解情况,还会显示标记为异常的其他值。


下图显示的是 github 页面上 Examples_Counts_Outlier_Detector 笔记本中的异常值(该笔记本使用的是简单的合成数据)。左侧窗格显示了 A 列的分布情况,绿色竖线表示分仓边缘,红色竖线表示标记的异常值。本示例使用 7 个仓(因此将数字特征分为 极低"、"低"、"中低"、"中"、"中高"、"高"、"极高")。


右侧窗格显示的是直方图。由于 5 个分区为空(该列中的所有值均为 "极低 "或 "极高"),因此这里只显示了 2 个分区。该图显示了该特征中 "非常高 "值的罕见程度,这些值比 "非常低 "值少得多,因此被视为异常值。


9


对于发现的任何二维异常,将显示散点图(在两个数字列的情况下)、带状图(在一个数字列和一个分类列的情况下)或热图(在两个分类列的情况下)。这将清楚地显示该值与 2d 空间中其他值的比较情况。


这里展示的是一个有两个数字特征的示例(来自 github 网站上的 demo_OpenML 笔记本)。除了散点图(左侧窗格)外,还显示了热图(右侧窗格),以显示每个分区的计数:


10


这使用的是 OpenML 的鲍鱼数据集(https://www.openml.org/search?type=data&sort=runs&id=183&status=active,以 CC BY 4.0 许可)。被解释的行(第 2407 行)在两幅图中都显示为星形。在本示例中,每个特征使用了 3 个二进制,因此 2d 空间有 9 个二进制。被解释的行所在的分区只有 36 条记录。相比之下,数据量最大的分区有 2212 条记录。


在散点图(左侧窗格)中,该仓中的其他记录显示为红色。其他箱中异常低计数的记录显示为黄色。


理解 1d 和 2d 异常值非常简单,因为可视化效果非常容易理解。三维和更高维度的异常值在概念上类似,但更难可视化。在维数较少的情况下,这种方法仍然很容易处理,但不如 1 维或 2 维那么简单。


对于超过 2 维的异常值,我们会绘制条形图,给出当前空间(特征组合)中每个值组合的计数,并给出上下文中被标记的值组合/箱的计数。


下面是对鲍鱼数据集中识别出的异常值行的部分解释,在本例中包含一个基于性别、直径和整重特征的 3d 异常值。


11


也可以调用 explain_features() API 进一步深入研究其中的任何一项。在本例中,它提供了每个组合的计数,我们可以看到上图中的组合(Sex=I, Diameter=Med; Whole_weight=Med)的计数仅为 12:


12


为了获得最高级别的可解释性,我建议将 max_dimensions 限制为 2,这样就可以只检查数据集中的 1d 和 2d 异常值,将结果以一维柱状图或直方图或二维图的形式呈现,这样就可以最完整地理解所呈现的空间。不过,使用三维或更多维(如上文的性别、直径和整重图)仍可进行合理解释。


准确性实验

虽然 COD 的优势在于其可解释性,但算法能否识别出最有意义的异常值而不会错误地标记出更典型的记录仍然很重要。


实验表明,计数异常值检测器与隔离森林(Isolation Forest)相比具有竞争力,至少在一种称为掺杂(doping)的测试形式中是如此:在真实数据集中修改少量数值(随机修改,但通常会产生异常记录,即特征之间不存在正常关联的记录),并测试异常值检测器是否能够识别出修改后的行。


还有其他有效的方法来评估异常值检测器,即使使用掺杂过程,数据修改的方式、掺杂的记录数量等也会有所不同。在这些测试中,COD 的表现略优于 Isolation Forest,但在其他测试中,Isolation Forest 可能比 COD 做得更好,其他检测器也可能如此。不过,这确实表明 COD 性能良好,在准确性方面可与标准异常值检测器媲美。


安装

该工具使用一个单独的类,即 CountsOutlierDetector,使用该工具的任何项目都需要包含该类。只需复制或下载定义该类的 .py 文件 counts_outlier_detector.py,并导入该类即可。


结论

该检测器具有以下优点


  1. 它能尽可能清晰地解释每一个异常值。为了解释某一行为什么会得到这样的分数,我们会使用尽可能多的特征来解释它的分数。
  2. 它能够提供每个空格的完整统计数据,从而提供每一行异常值的完整背景。


异常值检测领域普遍认为,每个检测器都能识别某些类型的异常值,通常使用多个检测器才能可靠地捕捉到数据集中的大部分异常值。COD 可能仅仅是出于这个目的而有用:它是一种直接、有用的异常值检测器,检测出的异常值可能与其他检测器有些不同。


文章来源:https://medium.com/towards-data-science/counts-outlier-detector-interpretable-outlier-detection-ead0d469557a
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
写评论取消
回复取消