哪种异常值检测可以检测到这些异常值?

数据挖掘 无监督学习 异常检测 离群值 分配
2021-10-03 15:35:49

我有一个向量,想检测其中的异常值。

下图显示了向量的分布。红点是异常值。蓝点是正常点。黄点也是正常的。

我需要一种异常值检测方法(一种非参数方法),它可以将红点检测为异常值。我测试了一些方法,如 IQR、标准差,但它们也将黄点检测为异常值。

我知道很难检测到红点,但我认为应该有一种方法(甚至方法组合)来解决这个问题。

在此处输入图像描述

积分是一天的传感器读数。但是由于系统重新配置(环境不是静态的),传感器的值会发生变化。重新配置的时间未知。蓝点是重新配置之前的时期。黄色点表示重新配置后导致读数分布出现偏差(但属于正常情况)。红点是非法修改黄点的结果。换句话说,它们是应该被检测到的异常。

我想知道内核平滑函数估计('pdf','survivor','cdf'等)是否有帮助。有人会帮助他们了解他们的主要功能(或其他平滑方法)以及在上下文中用于解决问题的理由吗?

3个回答

您可以将您的数据视为时间序列,其中普通测量产生的值非常接近前一个值,而重新校准产生的值与前一个值有很大差异。

以下是基于正态分布的模拟样本数据,具有与您的示例类似的三种不同方法。 在此处输入图像描述

通过计算与前一个值的差异(一种推导),您可以获得以下数据:

在此处输入图像描述

我对您的描述的解释是,您可以容忍重新校准(即距离零更远的点,图中的红色),但它们必须在正值和负值之间互换(即对应于从蓝色状态转变为黄色状态和背部)。

这意味着您可以设置一个警报,在负面或正面看到第二个红色点

如果您使用日志记录,则可以使用在配置更改时重置的运行平均值。但是,这将有一个弱点,即您至少需要一些数据才能检测到这样的异常值。

您的数据看起来相当“不错”(没有太多噪音)。我建议在相同配置中取最后 10-20 个点的平均值。如果这些值是某种计数量,您可以对单个数据点取泊松误差并计算平均误差。

你有多少历史数据?如果您有很多,您可以使用它来微调您的警报率,以便您捕获所有真实异常值的可接受比率,同时获得最少数量的虚假警告。什么是可接受的取决于具体问题。(误报成本或未检测到的异常值及其丰度)。

让我们用一个简单的例子来说明另一个答案中提出的方法

获取数据

我们将使用具有不同方法的正态分布生成的七个块来模拟数据。

这很重要,因为它使我们能够清晰地区分组并简单地检测断点。此答案使用基本阈值方法,您的真实数据可能需要一些更高级的方法。

dt <- rbind(
data.frame(color=1, x =  round(runif(50, min = 0, max = 50)), y = rnorm (50,mean=3.9, sd=.03)), 
data.frame(color=2, x =  round(runif(15, min = 50, max = 65)), y = rnorm (15,mean=4.5, sd=.03)),
data.frame(color=2, x =  round(runif(15, min = 65, max = 80)), y = rnorm (15,mean=3.3, sd=.03)),
data.frame(color=1, x =  round(runif(70, min = 80, max = 150)), y = rnorm (70,mean=3.9, sd=.03)), 
data.frame(color=2, x =  round(runif(15, min = 150, max = 165)), y = rnorm (15,mean=3.3, sd=.03)), 
data.frame(color=3, x =  round(runif(15, min = 165, max = 180)), y = rnorm (15,mean=2.9, sd=.03)), 
data.frame(color=1, x =  round(runif(120, min = 180, max = 300)), y = rnorm (120,mean=3.9, sd=.03))
)
dt$color <- as.factor(dt$color)
dt <- as_tibble(dt)

在此处输入图像描述

推导出断点

通过与前一点的简单差异,lag(y) 我们得到异常值。它们使用阈值进行分类。

在此处输入图像描述

行为分类的变化

根据您描述的规则,断点分为OKproblem

该规则规定不允许在同一方向进行两次更改。前一个方向的第二步被认为是一个问题。

如果你的逻辑更高级,你可能需要调整这个简单的解释。

## extract outliers and get previous value
dt2 <- filter(dt2, diff != 0) %>%
   mutate(cs = cumsum(diff),
          prev = lag(diff),
          cls = case_when(
                      diff * prev >  0 ~ "problem",
                      TRUE ~ "OK"))
## show 
dt2 %>% select(x,y,diff,prev,cls)                       
## # A tibble: 6 x 5
##       x     y  diff  prev cls    
##   <dbl> <dbl> <dbl> <dbl> <chr>  
## 1    50  4.53     1    NA OK     
## 2    66  3.32    -1     1 OK     
## 3    80  3.87     1    -1 OK     
## 4   151  3.32    -1     1 OK     
## 5   167  2.91    -1    -1 problem
## 6   180  3.87     1    -1 OK

推介会

最后,您将识别的异常值投影到原始数据

## project in the original data
ggplot(data=dt, mapping = aes(x=x, y=y) )  +
  geom_point(mapping = aes(color = color) )  +
  scale_color_manual(values=c("blue", "yellow", "red","green","red")) +
  theme(legend.position="none") +
  geom_vline(data=dt2, aes(xintercept=x, color=cls),
             linetype="dashed", size = 2)

在此处输入图像描述