// Performs a standard deviation, and returns StddevResults. If the data // set's length is less than 2, then an error will be returned along // with results of a standard deviation and average of zero. // These results may be inspected, however some // methods (such as LogProb) will fail. // // Based on the algorithm from RosettaCode, which can be found at: // http://rosettacode.org/wiki/Standard_deviation#Go, and // adapted for weighted standard deviation, the equation // for which which equation which was found at: // http://www.itl.nist.gov/div898/software/dataplot/refman2/ch2/weightsd.pdf func (s Stddev) Transform(analyzer *mino.Analyzer, data mino.Collection) (interface{}, error) { l := data.Len() // Special case: not enough data in set if l == 0 { return StddevResults{0, 0}, InsufficientDataError } else if l == 1 { return StddevResults{data.Next().Value, 0}, InsufficientDataError } var average, variance float64 n := float64(0) for data.HasMore() { x := data.Next() n += x.Weight a := average + (x.Value-average)/(n/x.Weight) variance, average = variance+(x.Value-average)*(x.Value-a)*x.Weight, a } besselLen := data.Len() if s.Bessel { besselLen -= 1 } return StddevResults{ Average: average, Deviation: math.Sqrt((float64(data.Len()) * variance) / (float64(besselLen) * data.Weight())), }, nil }
// Slices the data into sections, returning a slice of float64s. // Returns an error if the data set is empty. func (q Quartile) Transform(analyzer *mino.Analyzer, data mino.Collection) (interface{}, error) { sections := q.Sections if sections == 0 { sections = 4 } results := make([]float64, sections-1) dividend := (1 + data.Weight()) / float64(sections) // todo(connor4312): my algorithm below behaves oddly when the data // size is less than the number of requested sections. Whoever discovers // a solution to it is awarded three cookies. if data.Len() < sections { return results, InsufficientDataError } data.Sort(func(a, b mino.DataPoint) bool { return a.Value < b.Value }) var weight float64 var prev mino.DataPoint SECTION: for i := 1; i < sections; i++ { target := float64(i) * dividend for data.HasMore() { current := data.Next() last := prev prev = current if weight+current.Weight > target { frac := (target - weight) / current.Weight results[i-1] = last.Value*(1-frac) + current.Value*frac data.Rewind(1) continue SECTION } weight += current.Weight } results[i-1] = prev.Value } return results, nil }