-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathdbscan.go
90 lines (78 loc) · 2.27 KB
/
dbscan.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package dbscan
const (
NOISE = false
CLUSTERED = true
)
type Clusterable interface {
Distance(c interface{}) float64
GetID() string
}
type Cluster []Clusterable
func Clusterize(objects []Clusterable, minPts int, eps float64) []Cluster {
clusters := make([]Cluster, 0)
visited := map[string]bool{}
for _, point := range objects {
neighbours := findNeighbours(point, objects, eps)
if len(neighbours)+1 >= minPts {
visited[point.GetID()] = CLUSTERED
cluster := make(Cluster, 1)
cluster[0] = point
cluster = expandCluster(cluster, neighbours, visited, minPts, eps)
if len(cluster) >= minPts {
clusters = append(clusters, cluster)
}
} else {
visited[point.GetID()] = NOISE
}
}
return clusters
}
//Finds the neighbours from given array
//depends on Eps variable, which determines
//the distance limit from the point
func findNeighbours(point Clusterable, points []Clusterable, eps float64) []Clusterable {
neighbours := make([]Clusterable, 0)
for _, potNeigb := range points {
if point.GetID() != potNeigb.GetID() && potNeigb.Distance(point) <= eps {
neighbours = append(neighbours, potNeigb)
}
}
return neighbours
}
//Try to expand existing clutser
func expandCluster(cluster Cluster, neighbours []Clusterable, visited map[string]bool, minPts int, eps float64) Cluster {
seed := make([]Clusterable, len(neighbours))
copy(seed, neighbours)
for _, point := range seed {
pointState, isVisited := visited[point.GetID()]
if !isVisited {
currentNeighbours := findNeighbours(point, seed, eps)
if len(currentNeighbours)+1 >= minPts {
visited[point.GetID()] = CLUSTERED
cluster = merge(cluster, currentNeighbours)
}
}
if isVisited && pointState == NOISE {
visited[point.GetID()] = CLUSTERED
cluster = append(cluster, point)
}
}
return cluster
}
func merge(one []Clusterable, two []Clusterable) []Clusterable {
mergeMap := make(map[string]Clusterable)
putAll(mergeMap, one)
putAll(mergeMap, two)
merged := make([]Clusterable, 0)
for _, val := range mergeMap {
merged = append(merged, val)
}
return merged
}
//Function to add all values from list to map
//map keys is then the unique collecton from list
func putAll(m map[string]Clusterable, list []Clusterable) {
for _, val := range list {
m[val.GetID()] = val
}
}