-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathweighted_generalized_mean.go
95 lines (88 loc) · 2.58 KB
/
weighted_generalized_mean.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
package statistics
import (
"errors"
"math"
"github.com/theriault/maths"
)
// WeightedGeneralizedMean
//
// Time complexity: O(n)
// Space complexity: O(1)
//
// https://en.wikipedia.org/wiki/Generalized_mean
func WeightedGeneralizedMean[A maths.Integer | maths.Float, B maths.Integer | maths.Float](X []A, W []B, p float64) (float64, error) {
if len(X) == 0 {
return 0, errors.New("x must have at least 1 element")
}
if len(X) != len(W) {
return 0, errors.New("x and w are not the same lengths")
}
if p == 0 {
sumWeights := float64(0)
productPowers := float64(1)
for k, x := range X {
productPowers *= math.Pow(float64(x), float64(W[k]))
sumWeights += float64(W[k])
}
return math.Pow(productPowers, 1/sumWeights), nil
}
// as p approaches negative infinity, the general mean equals the minimum
if p == math.Inf(-1) {
min := float64(X[0])
minWeight := float64(W[0])
for k, x := range X {
if math.IsNaN(float64(x)) {
return math.NaN(), nil
}
if float64(x) < min {
min = float64(x)
minWeight = float64(W[k])
}
}
return min * minWeight, nil
}
// as p approaches positive infinity, the general mean equals the maximum
if p == math.Inf(+1) {
max := float64(X[0])
maxWeight := float64(W[0])
for k, x := range X {
if math.IsNaN(float64(x)) {
return math.NaN(), nil
}
if float64(x) > max {
max = float64(x)
maxWeight = float64(W[k])
}
}
return max * maxWeight, nil
}
sumWeights := float64(0)
sumPowers := float64(0)
for k, x := range X {
sumPowers += math.Pow(float64(W[k])*float64(x), p)
sumWeights += float64(W[k])
}
return math.Pow(sumPowers/sumWeights, 1/p), nil
}
// WeightedPowerMean is an alias for GeneralizedWeightedMean
func WeightedPowerMean[A maths.Integer | maths.Float, B maths.Integer | maths.Float](X []A, W []B, p float64) (float64, error) {
return WeightedGeneralizedMean(X, W, p)
}
// WeightedGeometricMean
//
// https://en.wikipedia.org/wiki/Weighted_geometric_mean
func WeightedGeometricMean[A maths.Integer | maths.Float, B maths.Integer | maths.Float](X []A, W []B) (float64, error) {
return WeightedPowerMean(X, W, 0)
}
// WeightedMean
//
// https://en.wikipedia.org/wiki/Weighted_arithmetic_mean
func WeightedMean[A maths.Integer | maths.Float, B maths.Integer | maths.Float](X []A, W []B) (float64, error) {
return WeightedPowerMean(X, W, 1)
}
// WeightedHarmonicMean
//
// https://en.wikipedia.org/wiki/Harmonic_mean#Weighted_harmonic_mean
func WeightedHarmonicMean[A maths.Integer | maths.Float, B maths.Integer | maths.Float](X []A, W []B) (float64, error) {
return WeightedPowerMean(X, W, -1)
}