photoprism/pkg/vector/stats.go
Michael Mayer 03129c9129 Vector: Reorganize package into topic-based files #4669
Split the catch-all values.go into one file per concept, each mirrored
by its test: distance.go, norm.go, stats.go, product.go, centroid.go,
plus the mean methods folded into mean.go and Copy/Dim/Sum into
vector.go. Remove values.go, values_test.go, and values_more_test.go so
functionality and tests live where developers expect them.

Hoist the two 512-dimensional face embeddings shared by the distance,
norm, and cosine tests into fixtures_test.go, removing the previous
triplication, and decompose the monolithic TestVector into per-concept
tests. Close pre-existing coverage gaps in the integer converters and
the GeometricMean/HarmonicMean method wrappers, bringing the package to
100% statement coverage. Pure code movement; no behavior change.
2026-05-30 09:44:03 +00:00

53 lines
971 B
Go

package vector
import "math"
// Sd calculates the vector's standard deviation.
func (v Vector) Sd() float64 {
return math.Sqrt(v.Variance())
}
// Variance calculates the vector's variance.
func (v Vector) Variance() float64 {
return v.variance(v.Mean())
}
// variance returns the sample variance around the given mean.
// Empty and single-element vectors have zero variance by convention,
// which also avoids a division by zero in the n-1 denominator.
func (v Vector) variance(mean float64) float64 {
n := float64(len(v))
if n < 2 {
return 0
}
ss := 0.0
for _, f := range v {
d := f - mean
ss += d * d
}
return ss / (n - 1)
}
// Cor returns the Pearson correlation between two vectors.
func Cor(a, b Vector) (float64, error) {
n := float64(len(a))
xy, err := Product(a, b)
if err != nil {
return NaN(), err
}
sx := a.Sd()
sy := b.Sd()
mx := a.Mean()
my := b.Mean()
r := (xy.Sum() - n*mx*my) / ((n - 1) * sx * sy)
return r, nil
}