mirror of
https://github.com/gonum/gonum.git
synced 2025-10-07 16:11:03 +08:00
stat: add BivariateMoment (#244)
* stat: add MixedMoment and fix bug in Moment code * Revert unrelated changes, rename to BivariateMoment * last fix
This commit is contained in:
35
stat/stat.go
35
stat/stat.go
@@ -862,6 +862,41 @@ func Mode(x, weights []float64) (val float64, count float64) {
|
|||||||
return max, maxCount
|
return max, maxCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BivariateMoment computes the weighted mixed moment between the samples x and y.
|
||||||
|
// E[(x - μ_x)^r*(y - μ_y)^s]
|
||||||
|
// No degrees of freedom correction is done.
|
||||||
|
// The lengths of x and y must be equal. If weights is nil then all of the
|
||||||
|
// weights are 1. If weights is not nil, then len(x) must equal len(weights).
|
||||||
|
func BivariateMoment(r, s float64, x, y, weights []float64) float64 {
|
||||||
|
meanX := Mean(x, weights)
|
||||||
|
meanY := Mean(y, weights)
|
||||||
|
if len(x) != len(y) {
|
||||||
|
panic("stat: slice length mismatch")
|
||||||
|
}
|
||||||
|
if weights == nil {
|
||||||
|
var m float64
|
||||||
|
for i, vx := range x {
|
||||||
|
vy := y[i]
|
||||||
|
m += math.Pow(vx-meanX, r) * math.Pow(vy-meanY, s)
|
||||||
|
}
|
||||||
|
return m / float64(len(x))
|
||||||
|
}
|
||||||
|
if len(weights) != len(x) {
|
||||||
|
panic("stat: slice length mismatch")
|
||||||
|
}
|
||||||
|
var (
|
||||||
|
m float64
|
||||||
|
sumWeights float64
|
||||||
|
)
|
||||||
|
for i, vx := range x {
|
||||||
|
vy := y[i]
|
||||||
|
w := weights[i]
|
||||||
|
m += w * math.Pow(vx-meanX, r) * math.Pow(vy-meanY, s)
|
||||||
|
sumWeights += w
|
||||||
|
}
|
||||||
|
return m / sumWeights
|
||||||
|
}
|
||||||
|
|
||||||
// Moment computes the weighted n^th moment of the samples,
|
// Moment computes the weighted n^th moment of the samples,
|
||||||
// E[(x - μ)^N]
|
// E[(x - μ)^N]
|
||||||
// No degrees of freedom correction is done.
|
// No degrees of freedom correction is done.
|
||||||
|
@@ -1094,6 +1094,63 @@ func TestMode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMixedMoment(t *testing.T) {
|
||||||
|
for i, test := range []struct {
|
||||||
|
x, y, weights []float64
|
||||||
|
r, s float64
|
||||||
|
ans float64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
x: []float64{10, 2, 1, 8, 5},
|
||||||
|
y: []float64{8, 15, 1, 6, 3},
|
||||||
|
r: 1,
|
||||||
|
s: 1,
|
||||||
|
ans: 0.48,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: []float64{10, 2, 1, 8, 5},
|
||||||
|
y: []float64{8, 15, 1, 6, 3},
|
||||||
|
weights: []float64{1, 1, 1, 1, 1},
|
||||||
|
r: 1,
|
||||||
|
s: 1,
|
||||||
|
ans: 0.48,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: []float64{10, 2, 1, 8, 5},
|
||||||
|
y: []float64{8, 15, 1, 6, 3},
|
||||||
|
weights: []float64{2, 3, 0.2, 8, 4},
|
||||||
|
r: 1,
|
||||||
|
s: 1,
|
||||||
|
ans: -4.786371011357490,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: []float64{10, 2, 1, 8, 5},
|
||||||
|
y: []float64{8, 15, 1, 6, 3},
|
||||||
|
weights: []float64{2, 3, 0.2, 8, 4},
|
||||||
|
r: 2,
|
||||||
|
s: 3,
|
||||||
|
ans: 1.598600579313326e+03,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
m := BivariateMoment(test.r, test.s, test.x, test.y, test.weights)
|
||||||
|
if math.Abs(test.ans-m) > 1e-14 {
|
||||||
|
t.Errorf("Moment mismatch case %d. Expected %v, found %v", i, test.ans, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !Panics(func() { BivariateMoment(1, 1, make([]float64, 3), make([]float64, 2), nil) }) {
|
||||||
|
t.Errorf("Moment did not panic with x, y length mismatch")
|
||||||
|
}
|
||||||
|
if !Panics(func() { BivariateMoment(1, 1, make([]float64, 2), make([]float64, 3), nil) }) {
|
||||||
|
t.Errorf("Moment did not panic with x, y length mismatch")
|
||||||
|
}
|
||||||
|
if !Panics(func() { BivariateMoment(1, 1, make([]float64, 2), make([]float64, 2), make([]float64, 3)) }) {
|
||||||
|
t.Errorf("Moment did not panic with x, weights length mismatch")
|
||||||
|
}
|
||||||
|
if !Panics(func() { BivariateMoment(1, 1, make([]float64, 2), make([]float64, 2), make([]float64, 1)) }) {
|
||||||
|
t.Errorf("Moment did not panic with x, weights length mismatch")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMoment(t *testing.T) {
|
func TestMoment(t *testing.T) {
|
||||||
for i, test := range []struct {
|
for i, test := range []struct {
|
||||||
x []float64
|
x []float64
|
||||||
|
Reference in New Issue
Block a user