// Copyright (c) 2012, Matt T. Proud // All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // statistics.go provides basic summary statistics functions for the purpose of // metrics aggregation. // TODO(mtp): Split this out into a summary statistics file once moving/rolling // averages are calculated. package maths import ( "math" "sort" ) // ReductionMethod provides a method for reducing metrics into a given scalar // value. type ReductionMethod func([]float64) float64 var Average ReductionMethod = func(input []float64) float64 { count := 0.0 sum := 0.0 for _, v := range input { sum += v count++ } if count == 0 { return math.NaN() } return sum / count } // Extract the first modal value. var FirstMode ReductionMethod = func(input []float64) float64 { valuesToFrequency := map[float64]int64{} var largestTally int64 = math.MinInt64 var largestTallyValue float64 = math.NaN() for _, v := range input { presentCount, _ := valuesToFrequency[v] presentCount++ valuesToFrequency[v] = presentCount if presentCount > largestTally { largestTally = presentCount largestTallyValue = v } } return largestTallyValue } // Calculate the percentile by choosing the nearest neighboring value. func NearestRank(input []float64, percentile float64) float64 { inputSize := len(input) if inputSize == 0 { return math.NaN() } ordinalRank := math.Ceil(((percentile / 100.0) * float64(inputSize)) + 0.5) copiedInput := make([]float64, inputSize) copy(copiedInput, input) sort.Float64s(copiedInput) preliminaryIndex := int(ordinalRank) - 1 if preliminaryIndex == inputSize { return copiedInput[preliminaryIndex-1] } return copiedInput[preliminaryIndex] } func NearestRankReducer(percentile float64) func(input []float64) float64 { return func(input []float64) float64 { return NearestRank(input, percentile) } } var Median ReductionMethod = NearestRankReducer(50) var Minimum ReductionMethod = func(input []float64) float64 { var minimum float64 = math.MaxFloat64 for _, v := range input { minimum = math.Min(minimum, v) } return minimum } var Maximum ReductionMethod = func(input []float64) float64 { var maximum float64 = math.SmallestNonzeroFloat64 for _, v := range input { maximum = math.Max(maximum, v) } return maximum }