package stats import "math" // Quartiles holds the three quartile points type Quartiles struct { Q1 float64 Q2 float64 Q3 float64 } // Quartile returns the three quartile points from a slice of data func Quartile(input Float64Data) (Quartiles, error) { il := input.Len() if il == 0 { return Quartiles{}, EmptyInputErr } // Start by sorting a copy of the slice copy := sortedCopy(input) // Find the cutoff places depeding on if // the input slice length is even or odd var c1 int var c2 int if il%2 == 0 { c1 = il / 2 c2 = il / 2 } else { c1 = (il - 1) / 2 c2 = c1 + 1 } // Empty halves make Median return ErrEmptyInput; propagate it instead of // returning NaN quartiles. Q1, err := Median(copy[:c1]) if err != nil { return Quartiles{}, err } Q2, err := Median(copy) if err != nil { return Quartiles{}, err } Q3, err := Median(copy[c2:]) if err != nil { return Quartiles{}, err } return Quartiles{Q1, Q2, Q3}, nil } // InterQuartileRange finds the range between Q1 and Q3 func InterQuartileRange(input Float64Data) (float64, error) { if input.Len() == 0 { return math.NaN(), EmptyInputErr } qs, err := Quartile(input) if err != nil { return math.NaN(), err } iqr := qs.Q3 - qs.Q1 return iqr, nil } // Midhinge finds the average of the first and third quartiles func Midhinge(input Float64Data) (float64, error) { if input.Len() == 0 { return math.NaN(), EmptyInputErr } qs, err := Quartile(input) if err != nil { return math.NaN(), err } mh := (qs.Q1 + qs.Q3) / 2 return mh, nil } // Trimean finds the average of the median and the midhinge func Trimean(input Float64Data) (float64, error) { if input.Len() == 0 { return math.NaN(), EmptyInputErr } c := sortedCopy(input) q, err := Quartile(c) if err != nil { return math.NaN(), err } return (q.Q1 + (q.Q2 * 2) + q.Q3) / 4, nil }