1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- package stats
- import "math"
- // Percentile finds the relative standing in a slice of floats
- func Percentile(input Float64Data, percent float64) (percentile float64, err error) {
- if input.Len() == 0 {
- return math.NaN(), EmptyInput
- }
- if percent <= 0 || percent > 100 {
- return math.NaN(), BoundsErr
- }
- // Start by sorting a copy of the slice
- c := sortedCopy(input)
- // Multiply percent by length of input
- index := (percent / 100) * float64(len(c))
- // Check if the index is a whole number
- if index == float64(int64(index)) {
- // Convert float to int
- i := int(index)
- // Find the value at the index
- percentile = c[i-1]
- } else if index > 1 {
- // Convert float to int via truncation
- i := int(index)
- // Find the average of the index and following values
- percentile, _ = Mean(Float64Data{c[i-1], c[i]})
- } else {
- return math.NaN(), BoundsErr
- }
- return percentile, nil
- }
- // PercentileNearestRank finds the relative standing in a slice of floats using the Nearest Rank method
- func PercentileNearestRank(input Float64Data, percent float64) (percentile float64, err error) {
- // Find the length of items in the slice
- il := input.Len()
- // Return an error for empty slices
- if il == 0 {
- return math.NaN(), EmptyInput
- }
- // Return error for less than 0 or greater than 100 percentages
- if percent < 0 || percent > 100 {
- return math.NaN(), BoundsErr
- }
- // Start by sorting a copy of the slice
- c := sortedCopy(input)
- // Return the last item
- if percent == 100.0 {
- return c[il-1], nil
- }
- // Find ordinal ranking
- or := int(math.Ceil(float64(il) * percent / 100))
- // Return the item that is in the place of the ordinal rank
- if or == 0 {
- return c[0], nil
- }
- return c[or-1], nil
- }
|