67 lines
1.9 KiB
Go
67 lines
1.9 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 "math"
|
||
|
|
||
|
// TODO: Implement histograms on top of scales.
|
||
|
|
||
|
type Histogram interface {
|
||
|
// Add adds a sample with value x to histogram h.
|
||
|
Add(x float64)
|
||
|
|
||
|
// Counts returns the number of samples less than the lowest
|
||
|
// bin, a slice of the number of samples in each bin,
|
||
|
// and the number of samples greater than the highest bin.
|
||
|
Counts() (under uint, counts []uint, over uint)
|
||
|
|
||
|
// BinToValue returns the value that would appear at the given
|
||
|
// bin index.
|
||
|
//
|
||
|
// For integral values of bin, BinToValue returns the lower
|
||
|
// bound of bin. That is, a sample value x will be in bin if
|
||
|
// bin is integral and
|
||
|
//
|
||
|
// BinToValue(bin) <= x < BinToValue(bin + 1)
|
||
|
//
|
||
|
// For non-integral values of bin, BinToValue interpolates
|
||
|
// between the lower and upper bounds of math.Floor(bin).
|
||
|
//
|
||
|
// BinToValue is undefined if bin > 1 + the number of bins.
|
||
|
BinToValue(bin float64) float64
|
||
|
}
|
||
|
|
||
|
// HistogramQuantile returns the x such that n*q samples in hist are
|
||
|
// <= x, assuming values are distibuted within each bin according to
|
||
|
// hist's distribution.
|
||
|
//
|
||
|
// If the q'th sample falls below the lowest bin or above the highest
|
||
|
// bin, returns NaN.
|
||
|
func HistogramQuantile(hist Histogram, q float64) float64 {
|
||
|
under, counts, over := hist.Counts()
|
||
|
total := under + over
|
||
|
for _, count := range counts {
|
||
|
total += count
|
||
|
}
|
||
|
|
||
|
goal := uint(float64(total) * q)
|
||
|
if goal <= under || goal > total-over {
|
||
|
return math.NaN()
|
||
|
}
|
||
|
for bin, count := range counts {
|
||
|
if count > goal {
|
||
|
return hist.BinToValue(float64(bin) + float64(goal)/float64(count))
|
||
|
}
|
||
|
goal -= count
|
||
|
}
|
||
|
panic("goal count not reached")
|
||
|
}
|
||
|
|
||
|
// HistogramIQR returns the interquartile range of the samples in
|
||
|
// hist.
|
||
|
func HistogramIQR(hist Histogram) float64 {
|
||
|
return HistogramQuantile(hist, 0.75) - HistogramQuantile(hist, 0.25)
|
||
|
}
|