87 lines
1.8 KiB
Go
87 lines
1.8 KiB
Go
|
package stats
|
||
|
|
||
|
import (
|
||
|
"math"
|
||
|
)
|
||
|
|
||
|
// Percentile finds the relative standing in a slice of floats
|
||
|
func Percentile(input Float64Data, percent float64) (percentile float64, err error) {
|
||
|
length := input.Len()
|
||
|
if length == 0 {
|
||
|
return math.NaN(), EmptyInputErr
|
||
|
}
|
||
|
|
||
|
if length == 1 {
|
||
|
return input[0], nil
|
||
|
}
|
||
|
|
||
|
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(), EmptyInputErr
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
|
||
|
}
|