-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathweighted_sum.go
60 lines (50 loc) · 1.77 KB
/
weighted_sum.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
package anomalia
import "math"
// WeightedSum holds the weighted sum algorithm configuration.
//
// The weighted sum algorithm uses a weighted sum to calculate anomalies scores.
// It should be used ONLY on small data-sets.
type WeightedSum struct {
scoreWeight float64
minEmaScore float64
*ExponentialMovingAverage
*Derivative
}
// NewWeightedSum returns weighted sum instance
func NewWeightedSum() *WeightedSum {
return &WeightedSum{
scoreWeight: 0.65,
minEmaScore: 0.94,
ExponentialMovingAverage: &ExponentialMovingAverage{2, 0.2},
Derivative: &Derivative{0.2},
}
}
// ScoreWeight sets Ema's score weight.
func (ws *WeightedSum) ScoreWeight(weight float64) *WeightedSum {
ws.scoreWeight = weight
return ws
}
// MinEmaScore sets the minimal Ema score above which the weighted score is used.
func (ws *WeightedSum) MinEmaScore(value float64) *WeightedSum {
ws.minEmaScore = value
return ws
}
// Run runs the weighted sum algorithm over the time series
func (ws *WeightedSum) Run(timeSeries *TimeSeries) *ScoreList {
scoreList, _ := ws.computeScores(timeSeries)
return scoreList
}
func (ws *WeightedSum) computeScores(timeSeries *TimeSeries) (*ScoreList, error) {
emaScores := ws.ExponentialMovingAverage.Run(timeSeries).Zip()
derivativeScores := ws.Derivative.Run(timeSeries).Zip()
scores := mapSlice(timeSeries.Timestamps, func(timestamp float64) float64 {
weightedScore := emaScores[timestamp]*ws.scoreWeight + derivativeScores[timestamp]*(1-ws.scoreWeight)
score := math.Max(emaScores[timestamp], weightedScore)
if emaScores[timestamp] > ws.minEmaScore {
return math.Max(score, derivativeScores[timestamp])
}
return score
})
scoreList := (&ScoreList{timeSeries.Timestamps, scores}).Denoise()
return scoreList, nil
}