Exemplo n.º 1
0
// 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
}
Exemplo n.º 2
0
// 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
}