101 lines
2.3 KiB
Go
101 lines
2.3 KiB
Go
// Copyright 2015 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package stats
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
)
|
|
|
|
// TODO(austin) Unify more with Sample interface
|
|
|
|
// StreamStats tracks basic statistics for a stream of data in O(1)
|
|
// space.
|
|
//
|
|
// StreamStats should be initialized to its zero value.
|
|
type StreamStats struct {
|
|
Count uint
|
|
Total, Min, Max float64
|
|
|
|
// Numerically stable online mean
|
|
mean float64
|
|
meanOfSquares float64
|
|
|
|
// Online variance
|
|
vM2 float64
|
|
}
|
|
|
|
// Add updates s's statistics with sample value x.
|
|
func (s *StreamStats) Add(x float64) {
|
|
s.Total += x
|
|
if s.Count == 0 {
|
|
s.Min, s.Max = x, x
|
|
} else {
|
|
if x < s.Min {
|
|
s.Min = x
|
|
}
|
|
if x > s.Max {
|
|
s.Max = x
|
|
}
|
|
}
|
|
s.Count++
|
|
|
|
// Update online mean, mean of squares, and variance. Online
|
|
// variance based on Wikipedia's presentation ("Algorithms for
|
|
// calculating variance") of Knuth's formulation of Welford
|
|
// 1962.
|
|
delta := x - s.mean
|
|
s.mean += delta / float64(s.Count)
|
|
s.meanOfSquares += (x*x - s.meanOfSquares) / float64(s.Count)
|
|
s.vM2 += delta * (x - s.mean)
|
|
}
|
|
|
|
func (s *StreamStats) Weight() float64 {
|
|
return float64(s.Count)
|
|
}
|
|
|
|
func (s *StreamStats) Mean() float64 {
|
|
return s.mean
|
|
}
|
|
|
|
func (s *StreamStats) Variance() float64 {
|
|
return s.vM2 / float64(s.Count-1)
|
|
}
|
|
|
|
func (s *StreamStats) StdDev() float64 {
|
|
return math.Sqrt(s.Variance())
|
|
}
|
|
|
|
func (s *StreamStats) RMS() float64 {
|
|
return math.Sqrt(s.meanOfSquares)
|
|
}
|
|
|
|
// Combine updates s's statistics as if all samples added to o were
|
|
// added to s.
|
|
func (s *StreamStats) Combine(o *StreamStats) {
|
|
count := s.Count + o.Count
|
|
|
|
// Compute combined online variance statistics
|
|
delta := o.mean - s.mean
|
|
mean := s.mean + delta*float64(o.Count)/float64(count)
|
|
vM2 := s.vM2 + o.vM2 + delta*delta*float64(s.Count)*float64(o.Count)/float64(count)
|
|
|
|
s.Count = count
|
|
s.Total += o.Total
|
|
if o.Min < s.Min {
|
|
s.Min = o.Min
|
|
}
|
|
if o.Max > s.Max {
|
|
s.Max = o.Max
|
|
}
|
|
s.mean = mean
|
|
s.meanOfSquares += (o.meanOfSquares - s.meanOfSquares) * float64(o.Count) / float64(count)
|
|
s.vM2 = vM2
|
|
}
|
|
|
|
func (s *StreamStats) String() string {
|
|
return fmt.Sprintf("Count=%d Total=%g Min=%g Mean=%g RMS=%g Max=%g StdDev=%g", s.Count, s.Total, s.Min, s.Mean(), s.RMS(), s.Max, s.StdDev())
|
|
}
|