Skip to content

Commit

Permalink
Merge pull request #109 from asturm-fe/107-dbscan-fill-pointlist-center
Browse files Browse the repository at this point in the history
107: Fill cluster.PointList and cluster.Center in DBScan()
  • Loading branch information
xiaogu-space committed Apr 23, 2024
2 parents e47d35d + 53dfa2c commit 770e5d7
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
5 changes: 4 additions & 1 deletion clusters/dbscan/dbscan.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ func DBScan(points clusters.PointList, eps float64, minPoints int) (clusterArray
if len(neighborPts) < minPoints {
noise = append(noise, i)
} else {
cluster := clusters.Cluster{C: C, Points: []int{i}}
// init cluster with center point
cluster := clusters.Cluster{C: C, Points: []int{i}, PointList: []space.Point{points[i]}}
members[i] = true
C++
// expandCluster goes here inline
Expand All @@ -63,9 +64,11 @@ func DBScan(points clusters.PointList, eps float64, minPoints int) (clusterArray

if !members[k] {
cluster.Points = append(cluster.Points, k)
cluster.PointList = append(cluster.PointList, points[k])
members[k] = true
}
}
cluster.Recenter()
clusterArray = append(clusterArray, cluster)
}
}
Expand Down
33 changes: 33 additions & 0 deletions clusters/dbscan/dbscan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ func TestRangeQueryKDTree(t *testing.T) {
}

func TestDBScan(t *testing.T) {
setup()
clusterArray, noise := DBScan(s.points, 0.8, 10)

goodClusters := []clusters.Cluster{
Expand Down Expand Up @@ -157,4 +158,36 @@ func TestDBScan(t *testing.T) {
return
}
}

// Verify cluster.PointList contains the correct points
for _, cluster := range clusterArray {
if len(cluster.Points) != len(cluster.PointList) {
t.Errorf("Cluster #%d cluster.Points contains %d points, while cluster.Pointlist contains %d points. Must be the same!", cluster.C, len(cluster.Points), len(cluster.PointList))
return
}
// cluster.Points has been sorted, but cluster.PointList has not so we have to loop cluster.PointList for each cluster.Point to find the match
// multiple matches are allowed as a cluster can contain multiple points with the same coordinates
matchedPoints := make(map[int]bool, len(cluster.Points))
for _, pointIdx := range cluster.Points {
for _, point := range cluster.PointList {
if reflect.DeepEqual(s.points[pointIdx], point) {
matchedPoints[pointIdx] = true
}
}
}
// every index in cluster.Points must have a match in cluster.PointList
for _, pointIdx := range cluster.Points {
if !matchedPoints[pointIdx] {
t.Errorf("Cluster #%d pointIdx %d (%v) has no match in cluster.PointList", cluster.C, pointIdx, s.points[pointIdx])
return
}
}
}

// Verify cluster.Center is filled
for _, cluster := range clusterArray {
if cluster.Center == nil || len(cluster.Center) == 0 {
t.Errorf("cluster.Center should not be empty")
}
}
}

0 comments on commit 770e5d7

Please sign in to comment.