我目前正在使用R语言实现DBSCAN算法来查找数据中的异常值。为了初始化参数(特别是epsilon),我需要绘制样本中到第k个邻居(我选择了k = 3
)的距离的升序排序序列,并观察肘部位置以选择epsilon的正确值。
正如我所说,我使用的是R统计语言,我发现有两个不同的函数来计算到第k个邻居的距离,分别是nndist()
和kNNdist()
。如果我理解正确的话,默认情况下它使用欧几里得距离。然而,在我的数据中,这两个函数显示的结果并不相同。为了说明我的问题,我在著名的iris
数据集上实现了这两个函数,你可以看到结果差异很大:
data(iris)iris <- as.matrix(iris[,1:4])distance_third_neighbour_iris = iris %>% nndist(k = 3)as.vector(quantile(distance_third_neighbour_iris, probs = 0.99))### 结果为0.68distance_third_neighbour_iris = iris %>% kNNdist(k = 3)as.vector(quantile(distance_third_neighbour_iris, probs = 0.99))### 结果为0.81
显然,这两个函数默认情况下似乎没有使用相同的距离或计算方法。
回答:
你这里有几个问题:
-
当
nndist
接受一个矩阵作为输入时,它假设它只是二维的。为了将iris
数据集的四个列作为四维点接受,并触发nndist
的多维版本——即nndist.ppx
——你首先需要将iris
转换为ppx
点,像这样:ppx(iris)
-
即使解决了第一个问题,结果仍然会不同。这是因为
kNNdist
不仅仅产生到k=3邻居的距离,而是生成一个包含到k=3为止的所有距离(即k=1, k=2, 和k=3)的数据框的列。因此,当你试图仅获取k=3的值并希望将其与nndist
的结果进行比较时,你应该仅使用第三列,像这样:distance_third_neighbour_iris_knndist[,3]
因此,你的代码应该修改为:
library(dbscan)library(spatstat)data(iris)iris <- as.matrix(iris[,1:4])distance_third_neighbour_iris_nndist = ppx(iris) %>% nndist(k = 3)as.vector(quantile(distance_third_neighbour_iris_nndist, probs = 0.99))### 结果为0.8776718distance_third_neighbour_iris_knndist = iris %>% kNNdist(k = 3)as.vector(quantile(distance_third_neighbour_iris_knndist[,3], probs = 0.99))### 结果为0.8776718