检测高斯混合中的异常值

机器算法验证 正态分布 异常值 混合分布
2022-04-07 03:12:50

我有大量的单变量样本()。我想要一种自动化方法来检查异常值并识别异常值(如果存在)。非异常值分布的合理模型是高斯混合。混合物中的高斯数及其参数是先验未知的。你能推荐一种识别异常值的简单方法吗?你有什么建议?如果用 Python 编写代码很简单,那就太好了。xiR+

快速而肮脏的东西——比如说,易于理解、易于实施且非常有效——胜过复杂但最佳的东西。例如,基于期望最大化,我有点不愿意涉足一些花哨的事情。

示例参数:我可能有 10,000 个左右的样本。非异常值的分布可能是 2 个高斯的混合;或者我可能有几百个高斯的混合体。

更新:考虑到这些假设,人们问任何事情怎么可能是异常值。(据推测,未说明的问题是这个问题可能无法解决:如果每个数据集总是可以用某种混合模型解释,那么就没有任何基础可以将任何东西识别为异常值。)这是一个公平的问题,所以让我试着回答一下. 在我的应用领域,我可以合理地假设每个高斯分量都会有几十个样本。例如,我可能有来自 100 个高斯混合的 40,000 个样本,其中每个高斯分量的概率不低于 0.001(因此几乎可以保证每个高斯至少有 10 个样本)。我意识到我之前没有陈述这个假设,我为此道歉。然而,有了这个额外的假设,我相信这个问题是可以解决的。存在可以将一个或多个点视为异常值的数据集示例(任何混合模型都无法合理地解释它们)。例如,考虑一个数据集,其中一个孤立点与其他所有点相距甚远:如果距离足够远,则无法用高斯混合模型解释,因此可以识别为异常值。总之,我相信这个问题是明确定义的并且是可以解决的(考虑到此处所述的附加假设):确实存在一些可以合理地将某些点识别为异常值的示例情况。它不能用高斯混合模型解释,因此可以被识别为异常值。总之,我相信这个问题是明确定义的并且是可以解决的(考虑到此处所述的附加假设):确实存在一些可以合理地将某些点识别为异常值的示例情况。它不能用高斯混合模型解释,因此可以被识别为异常值。总之,我相信这个问题是明确定义的并且是可以解决的(考虑到此处所述的附加假设):确实存在一些可以合理地将某些点识别为异常值的示例情况。

请注意,我并不是要对异常值提出特殊或不寻常的定义。我很高兴使用异常值的标准概念(例如,无法合理解释为由假设过程生成的点,因为它不太可能由该过程生成)。

4个回答

我在评论中建议,这种情况下的“异常值”可能被定义为以“极端”值为中心的“小”集群的成员。 引用术语的含义需要量化,但显然它们可以是:“小”将是少于 10 个值的集群,“极端”可以确定为相对于混合模型中的组件均值集的离群值。 在这种情况下,可以通过对任何合理的数据聚类分析进行简单的后处理来找到异常值。

在微调这种方法时必须做出选择。这些选择将取决于数据的性质,因此不能在这样的一般答案中完全指定。相反,让我们分析一些数据。 我使用R它是因为它在这个网站上的流行和简洁(甚至与 Python 相比)。

首先,按照问题中的描述创建一些数据:

set.seed(17) # For reproducible results
centers <- rnorm(100, mean=100, sd=20)
x <- c(centers + rnorm(100*100, mean=0, sd=1), 
       rnorm(100, mean=250, sd=1), 
       rnorm(9, mean=300, sd=1))

该命令指定了 102 个组件:其中 100 个位于正态 (100, 20) 分布中的 100 个独立抽取(因此往往位于 50 到 150 之间);其中一个以 250 为中心,一个以 300 为中心。然后,它独立于每个组件绘制 100 个值(使用 1 的常见标准偏差),但在以 300 为中心的最后一个组件中,它仅绘制 9 个值。根据异常值的表征,以 250 为中心的 100 个值并不构成异常值:它们应该被视为混合物的一个组成部分,尽管它们的位置远离其他值。然而,一组九个高值完全由异常值组成。 我们需要检测这些,但不需要检测其他。

大多数综合单变量异常值检测程序要么不会检测到这 109 个最高值中的任何一个,要么会指示所有 109 个都是异常值。

假设我们对组件的标准偏差有很好的了解(从先验信息或从探索数据中获得)。使用它来构造混合物的核密度估计:

d <- density(x, bw=1, n=1000)
plot(d, main="Kernel density")

KDE

最右边的(几乎不可见的)blip 有资格作为一组异常值:它的小区域(小于总数的 10/10109 = 0.001)表明它仅包含几个值,并且它的情况位于 x- 的一个极端轴为其赢得了“异常值”而不是“内部值”的称号。检查这些事情很简单:

x0 <- d$x[d$y > 1000/length(x) * dnorm(5)]
gaps <- tail(x0, -1) - head(x0, -1)
histogram(gaps, main="Gap Counts")

间隙直方图

密度估计d由 1000 个 bin 的一维网格表示。这些命令保留了所有密度足够大的 bin。对于“大”,我选择了一个非常小的值,以确保即使单个孤立值的密度也被拾取,但不会太小以至于明显分离的组件被合并。

显然,间隙分布有两个高异常值(可以使用任何简单的程序自动检测到,甚至是临时程序)。一个特征是它们都超过 25(在这个例子中)。让我们找到与它们关联的值:

large.gaps <- gaps > 25
ranges <- rbind(tail(x0,-1)[large.gaps], c(tail(head(x0,-1)[large.gaps], -1), max(x))

输出是

         [,1]     [,2]
[1,] 243.9937 295.7732
[2,] 256.3758 300.9340

在数据范围内(从 25 到 301),这些差距决定了两个潜在的异常范围,一个从 244 到 256(第 1 列),另一个从 296 到 301(第 2 列)。让我们看看有多少值位于这些范围内:

lapply(apply(ranges, 2, function(r){x[r[1] <= x & x <= r[2]]}), length)

结果是

[[1]]
[1] 100

[[2]]
[1] 9

100 太大了以至于不寻常:这是混合物的成分之一。但是9已经足够小了。仍有待观察这些组件中的任何一个是否可能被认为是异常的(而不是内部的):

apply(ranges, 2, mean)

结果是

[1] 250.1848 298.3536

100 点聚类的中心在 250,9 点聚类的中心在 298,与其余数据的距离足以构成异常值聚类。 我们得出结论有九个异常值具体来说,这些是由 的第 2 列确定的值ranges

x[ranges[1,2] <= x & x <= ranges[2,2]]

按顺序,它们是

299.0379 300.0376 300.2696 300.3892 300.4250 300.5659 300.7018 300.8436 300.9340

我不确定我是否理解这里的问题,但 MAD-Median 规则:

|XM|MADN>2.24, 在哪里M是中位数和MADN是个median absolute deviation from the median0.6745

很常用。Wilcox 在 R 中的 WRS 包有一个out()适合此的函数,并返回要保留的案例和要删除的案例,我相信用其他语言编写代码会很容易。从表面上看,这将是您问题的答案 - 当然是众多问题之一,因为有大量关于异常值的文献。

当然,您可能需要对“异常值”进行更严格的定义。如果您对与 100 多个高斯变量的混合分布一致的任何观察结果感到满意,那么很难想象有任何东西被排除为异常值。

如果您的非异常值的可能分布范围如此广泛,我认为您不会有任何异常值。但也许你可以对混合物施加一些限制?

例如,如果 N = 10,000 并且它是N (9900,10,10)N (100,50,100)那么一些非常大的值将是非异常值。

此外,一般来说,自动搜索异常值只能是第一步。

我能想到的最优雅的解决方案是混合高斯模型,其中您有 k 个与您的信号相对应的高斯(事先鼓励它们的方差相当小),以及 1 个漫反射高斯捕获异常值(“漫反射”意味着巨大的差异),您可以在其中指定 Dirichlet 先验中异常值的先验比例(例如 1%)。如果不想做 EM,可以考虑使用 k-means 作为热启动,然后迭代优化,其中慢步是离散聚类分配的优化。但是,如果信号高斯的(协)方差大致相等,这意味着大多数重新分配将来自/来自相邻集群,或者来自/来自异常值集群。