让我们用一个简单的例子来说明另一个答案中提出的方法
获取数据
我们将使用具有不同方法的正态分布生成的七个块来模拟数据。
这很重要,因为它使我们能够清晰地区分组并简单地检测断点。此答案使用基本阈值方法,您的真实数据可能需要一些更高级的方法。
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)
我们得到异常值。它们使用阈值进行分类。
行为分类的变化
根据您描述的规则,断点分为OK
和problem
。
该规则规定不允许在同一方向进行两次更改。前一个方向的第二步被认为是一个问题。
如果你的逻辑更高级,你可能需要调整这个简单的解释。
## 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)