-
Notifications
You must be signed in to change notification settings - Fork 1
/
lof.go
97 lines (72 loc) · 1.83 KB
/
lof.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
91
92
93
94
95
96
97
package anomaly
import (
"math"
"sort"
)
type LOFResult struct {
Value float64
LofScore float64
}
func GetMedianFromLofResults(lofResults []LOFResult) float64 {
var data []float64
for _, result := range lofResults {
data = append(data, result.LofScore)
}
sort.Float64s(data)
length := len(data)
if length%2 == 1 {
return data[length/2]
}
return (data[length/2-1] + data[length/2]) / 2
}
func LocalOutlierFactor(data []float64) []LOFResult {
var lofResults []LOFResult
for _, point := range data {
reachDistances := CalculateReachabilityDistances(point, data)
lof := CalculateLOF(reachDistances)
newLofResult := LOFResult{Value: point, LofScore: lof}
lofResults = append(lofResults, newLofResult)
}
return lofResults
}
func CalculateReachabilityDistances(point float64, data []float64) []float64 {
distances := make([]float64, len(data))
for i, neighbor := range data {
distances[i] = EuclideanDistance(point, neighbor)
}
return distances
}
func CalculateLOF(reachDistances []float64) float64 {
lrd := 0.0
for _, reachDistance := range reachDistances {
lrd += reachDistance
}
lrd /= float64(len(reachDistances))
lof := 0.0
for _, reachDistance := range reachDistances {
lof += reachDistance / lrd
}
lof /= float64(len(reachDistances))
lof /= lrd
return lof
}
func EuclideanDistance(p1, p2 float64) float64 {
return math.Abs(p1 - p2)
}
func CalculateStandardDeviation(lofResults []LOFResult) float64 {
scores := make([]float64, len(lofResults))
sum := 0.0
// mean
for i, result := range lofResults {
scores[i] = result.LofScore
sum += result.LofScore
}
mean := sum / float64(len(lofResults))
// standard deviation
varianceSum := 0.0
for _, score := range scores {
varianceSum += math.Pow(score-mean, 2)
}
variance := varianceSum / float64(len(lofResults))
return math.Sqrt(variance)
}