// 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()) }