DBSCAN(D, eps, MinPts)
C = 0
for each unvisited point P in dataset D
mark P as visited
NeighborPts = regionQuery(P, eps)
if sizeof(NeighborPts) < MinPts
mark P as NOISE
else
C = next cluster
expandCluster(P, NeighborPts, C, eps, MinPts)
expandCluster(P, NeighborPts, C, eps, MinPts)
add P to cluster C
for each point P' in NeighborPts
if P' is not visited
mark P' as visited
NeighborPts' = regionQuery(P', eps)
if sizeof(NeighborPts') >= MinPts
NeighborPts = NeighborPts joined with NeighborPts'
if P' is not yet member of any cluster
add P' to cluster C
regionQuery(P, eps)
return all points within P's eps-neighborhood
以上是。正如你所看到的,根据维基百科的DBSCAN算法。
我想问一下这个确切的部分。
NeighborPts = NeighborPts joined with NeighborPts'
我的理解是,如果访问核心点邻居的核心点,它将加入当前检查的集群,对吧?但递归是如何发生在这里的?因为我们定义了循环:
for each point P' in NeighborPts
在加入过程之前,所以来自NeighborPts的任何附加点都不会被expandCluster函数检查,如果新的NeighborPts实际上有一个点是同一个集群的另一个核心点,那么算法进行?
我有一个代码在Java中实现'expandCluster'方法:
public void expand(Vector<Integer> region, Group c, double dist, int minPts){
for(int i = 0; i < region.size(); i++){
int idx = region.get(i);
if(labels[idx] == 0){ // check if point is visited
labels[idx] = 1; // mark as visited
Vector<Integer> v = region(idx, dist); // check for neighboring point
if (v.size() >= minPts){ // check if core point
region.addAll(v); // join the NeighborPts
}
}
if(clustered[idx] == 0){
c.elements.add(patterns.get(idx));
clustered[idx] = clusters.size()+1;
}
}
}
在通过此代码region
修改数据集后,是否会重新访问数据集region.addAll(v);
?
答案 0 :(得分:1)
我的理解是,如果来自核心邻居的核心点 访问点,它将加入当前检查的集群, 正确?
是的,你是对的,你可以安全地删除该行
如果没有访问P'
然而,这效率不高。
如果已经访问过点P',则无需计算其邻域并将其与P的邻域连接。
访问意味着:它是一个噪点,它已经在一个集群中,或者它是一个边界点。 如果它已经在一个集群中并且它是一个核心点,这意味着它的邻居已经被处理过了。 如果它是一个边界点,则其邻居不得加入。
但这次递归是怎么发生的?
在第
行对于NeighborPts中的每个点P'
您必须将NeighborPts
视为积分的动态容器。第一次输入for循环时,NeighborPts
包含X
个点。如果加入会将Y
点添加到NeighborPts
,则for循环将同时访问X
和Y
个集合。然后,这将对集合X
和Y
重复,这就是递归的发生方式。
数据收集区域将在之后重新访问 通过此代码修改数据集合 region.addAll(V);
是的,每次拨打region.addAll(v)
时,region.size()
都会增加,这会确认让您感到困惑的递归行为。