percentile.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. package stats
  2. import "math"
  3. // Percentile finds the relative standing in a slice of floats
  4. func Percentile(input Float64Data, percent float64) (percentile float64, err error) {
  5. if input.Len() == 0 {
  6. return math.NaN(), EmptyInput
  7. }
  8. if percent <= 0 || percent > 100 {
  9. return math.NaN(), BoundsErr
  10. }
  11. // Start by sorting a copy of the slice
  12. c := sortedCopy(input)
  13. // Multiply percent by length of input
  14. index := (percent / 100) * float64(len(c))
  15. // Check if the index is a whole number
  16. if index == float64(int64(index)) {
  17. // Convert float to int
  18. i := int(index)
  19. // Find the value at the index
  20. percentile = c[i-1]
  21. } else if index > 1 {
  22. // Convert float to int via truncation
  23. i := int(index)
  24. // Find the average of the index and following values
  25. percentile, _ = Mean(Float64Data{c[i-1], c[i]})
  26. } else {
  27. return math.NaN(), BoundsErr
  28. }
  29. return percentile, nil
  30. }
  31. // PercentileNearestRank finds the relative standing in a slice of floats using the Nearest Rank method
  32. func PercentileNearestRank(input Float64Data, percent float64) (percentile float64, err error) {
  33. // Find the length of items in the slice
  34. il := input.Len()
  35. // Return an error for empty slices
  36. if il == 0 {
  37. return math.NaN(), EmptyInput
  38. }
  39. // Return error for less than 0 or greater than 100 percentages
  40. if percent < 0 || percent > 100 {
  41. return math.NaN(), BoundsErr
  42. }
  43. // Start by sorting a copy of the slice
  44. c := sortedCopy(input)
  45. // Return the last item
  46. if percent == 100.0 {
  47. return c[il-1], nil
  48. }
  49. // Find ordinal ranking
  50. or := int(math.Ceil(float64(il) * percent / 100))
  51. // Return the item that is in the place of the ordinal rank
  52. if or == 0 {
  53. return c[0], nil
  54. }
  55. return c[or-1], nil
  56. }