有效地确定数据集中的点是否没有近邻

时间:2018-06-23 10:00:43

标签: r distance nearest-neighbor

我有一个大约有1万个点的数据集,每个点都有200个数字描述符。 在这10K点中,我想定位离群值,我将其定义为离其最近的10个近邻较远的离群值(距离多远?与第10个近邻的距离就等于离第10个邻点的其他距离) ,离群值则照常定义。)

我尝试计算整个距离矩阵(10K x 10K),对每一行应用部分排序以查找10个最近的邻居。太贵了。

我还检查了快速kNN选项,但它们也太昂贵了。

我认为可以更有效地完成此操作的原因是,我们并不真正在乎实际距离,而只是在乎它们的相对等级。

可以如下生成样本数据矩阵:

df = matrix(rnorm(2000000), nrow = 10000, ncol = 200)

有创意吗?

2 个答案:

答案 0 :(得分:1)

  • 首先提出一个问题,为什么所有10个最近的邻居都相距遥远?是否要避免9个异常值彼此接近的情况?
  • 什么是“太慢”?您尝试过类似CoverTree的事情吗?它具有非常快的kNN以实现高维度。
  • 加快速度:您是否尝试过使用L1 / Manhattan / Taxi距离?它往往比欧几里得距离快。
  • 通常来说,随着维数的增加,kNN变得越来越无意义,因为除非您拥有高度聚类的数据集,否则所有点的平均距离趋于相等。
  • 一个一般的想法:如果您以某种方式计算了已知的“到远”的距离,则可以简单地使用窗口查询来检查“太远”距离内是否还有其他点。在这里,我建议使用PH-Tree,它具有非常快速的窗口查询,尤其是在结果大小较小(0或1个匹配)时。它也可以调整为在1次或10次点击后中止窗口,并仅返回有更多点击(或没有点击)。这应该比kNN快。问题是,至少在使用L2距离(欧几里得)时,窗口查询在具有高维数时变得效率越来越低。 L1应该更有效。
  • 另外,请查看K-means clustering。它对此了解不多,但也可能提供异常检测。至少,它应该为您提供一种确定“太远”的距离的方法。
  • 机器学习中使用的一种技术(例如)是降维。这有点棘手,但是如果您可以将维数减少到10左右,则kNN算法(或任何其他算法)可能会更快,

编辑

我使用Java实现在计算机(I7-4790)上进行了一些性能测试:数据集具有10K点和200个维度(点略有聚集,每个维度在0.0和1.0之间)。

  • CoverTree:加载10000点需要1.6秒。 10000个最近的邻居查询大约需要3.1秒。
  • PH树:加载10000点需要0.07秒。 10000个窗口查询(选择的窗口大小为平均结果大小= 1)约为5.5秒。

答案 1 :(得分:0)

这是个主意, 尽管我怀疑它是否适用于随机数据。

# primarily for lag and lead
library(dplyr)

# sample data
df <- mtcars %>%
  select(mpg, disp, drat, wt, qsec) %>%
  do(as.data.frame(scale(.))) %>%
  filter_all(all_vars(!duplicated(.)))

knn <- 4L
distance <- 0.3

colwise_outlier <- sapply(1L:ncol(df), function(j) {
  column <- df[, j]
  order_ids <- order(column)
  column <- column[order_ids]

  n <- (knn + 2L) %/% 2L
  outlier <- column - lag(column, n=n, default=-Inf) > distance & 
    lead(column, n=n, default=Inf) - column > distance

  # return with original order
  outlier[order_ids]
})

is_outlier <- apply(colwise_outlier, 1L, function(r) {
  Reduce("&", r)
})

outliers <- df[is_outlier,]

它的作用是首先隔离检查每一列, 并且仅当最多knn个值在其distance之内时才将该行标记为异常值。 然后,仅在所有列中都满足此条件的行中保存。

编辑:甚至可以为每列设置不同的distance值, 以防您的数据未规范化。