algorithm for calculating variance (default: VarianceAlgo.online)
algorithm for calculating sums (default: Summation.appropriate)
The standard deviation of the input, must be floating point type type
import mir.math.common: approxEqual, sqrt; import mir.ndslice.slice: sliced; assert(standardDeviation([1.0, 2, 3]).approxEqual(sqrt(2.0 / 2))); assert(standardDeviation([1.0, 2, 3], true).approxEqual(sqrt(2.0 / 3))); assert(standardDeviation!float([0, 1, 2, 3, 4, 5].sliced(3, 2)).approxEqual(sqrt(17.5 / 5))); static assert(is(typeof(standardDeviation!float([1, 2, 3])) == float));
Standard deviation of vector
import mir.math.common: approxEqual, sqrt; import mir.ndslice.slice: sliced; auto x = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25, 2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced; assert(x.standardDeviation.approxEqual(sqrt(54.76562 / 11)));
Standard deviation of matrix
import mir.math.common: approxEqual, sqrt; import mir.ndslice.fuse: fuse; auto x = [ [0.0, 1.0, 1.5, 2.0, 3.5, 4.25], [2.0, 7.5, 5.0, 1.0, 1.5, 0.0] ].fuse; assert(x.standardDeviation.approxEqual(sqrt(54.76562 / 11)));
Column standard deviation of matrix
import mir.algorithm.iteration: all; import mir.math.common: approxEqual, sqrt; import mir.ndslice.fuse: fuse; import mir.ndslice.topology: alongDim, byDim, map; auto x = [ [0.0, 1.0, 1.5, 2.0], [3.5, 4.25, 2.0, 7.5], [5.0, 1.0, 1.5, 0.0] ].fuse; auto result = [13.16667 / 2, 7.041667 / 2, 0.1666667 / 2, 30.16667 / 2].map!sqrt; // Use byDim or alongDim with map to compute standardDeviation of row/column. assert(x.byDim!1.map!standardDeviation.all!approxEqual(result)); assert(x.alongDim!0.map!standardDeviation.all!approxEqual(result)); // FIXME // Without using map, computes the standardDeviation of the whole slice // assert(x.byDim!1.standardDeviation == x.sliced.standardDeviation); // assert(x.alongDim!0.standardDeviation == x.sliced.standardDeviation);
Can also set algorithm type
import mir.math.common: approxEqual, sqrt; import mir.ndslice.slice: sliced; auto a = [0.0, 1.0, 1.5, 2.0, 3.5, 4.25, 2.0, 7.5, 5.0, 1.0, 1.5, 0.0].sliced; auto x = a + 1_000_000_000; auto y = x.standardDeviation; assert(y.approxEqual(sqrt(54.76562 / 11))); // The naive algorithm is numerically unstable in this case auto z0 = x.standardDeviation!"naive"; assert(!z0.approxEqual(y)); // But the two-pass algorithm provides a consistent answer auto z1 = x.standardDeviation!"twoPass"; assert(z1.approxEqual(y));
Can also set algorithm or output type
import mir.math.common: approxEqual, sqrt; import mir.ndslice.slice: sliced; import mir.ndslice.topology: repeat; //Set population standard deviation, standardDeviation algorithm, sum algorithm or output type auto a = [1.0, 1e100, 1, -1e100].sliced; auto x = a * 10_000; bool populationTrueRT = true; bool populationFalseRT = false; enum PopulationTrueCT = true; /++ Due to Floating Point precision, when centering `x`, subtracting the mean from the second and fourth numbers has no effect. Further, after centering and squaring `x`, the first and third numbers in the slice have precision too low to be included in the centered sum of squares. +/ assert(x.standardDeviation(populationFalseRT).approxEqual(sqrt(2.0e208 / 3))); assert(x.standardDeviation(populationTrueRT).approxEqual(sqrt(2.0e208 / 4))); assert(x.standardDeviation(PopulationTrueCT).approxEqual(sqrt(2.0e208 / 4))); assert(x.standardDeviation!("online").approxEqual(sqrt(2.0e208 / 3))); assert(x.standardDeviation!("online", "kbn").approxEqual(sqrt(2.0e208 / 3))); assert(x.standardDeviation!("online", "kb2").approxEqual(sqrt(2.0e208 / 3))); assert(x.standardDeviation!("online", "precise").approxEqual(sqrt(2.0e208 / 3))); assert(x.standardDeviation!(double, "online", "precise").approxEqual(sqrt(2.0e208 / 3))); assert(x.standardDeviation!(double, "online", "precise")(populationTrueRT).approxEqual(sqrt(2.0e208 / 4))); auto y = uint.max.repeat(3); auto z = y.standardDeviation!ulong; assert(z == 0.0); static assert(is(typeof(z) == double));
For integral slices, pass output type as template parameter to ensure output type is correct.
import mir.math.common: approxEqual, sqrt; import mir.ndslice.slice: sliced; auto x = [0, 1, 1, 2, 4, 4, 2, 7, 5, 1, 2, 0].sliced; auto y = x.standardDeviation; assert(y.approxEqual(sqrt(50.91667 / 11))); static assert(is(typeof(y) == double)); assert(x.standardDeviation!float.approxEqual(sqrt(50.91667 / 11)));
Variance works for other user-defined types (provided they can be converted to a floating point)
import mir.ndslice.slice: sliced; static struct Foo { float x; alias x this; } Foo[] foo = [Foo(1f), Foo(2f), Foo(3f)]; assert(foo.standardDeviation == 1f);
Compute standard deviation along specified dimention of tensors
import mir.algorithm.iteration: all; import mir.math.common: approxEqual, sqrt; import mir.ndslice.fuse: fuse; import mir.ndslice.topology: as, iota, alongDim, map, repeat; auto x = [ [0.0, 1, 2], [3.0, 4, 5] ].fuse; assert(x.standardDeviation.approxEqual(sqrt(17.5 / 5))); auto m0 = repeat(sqrt(4.5), 3); assert(x.alongDim!0.map!standardDeviation.all!approxEqual(m0)); assert(x.alongDim!(-2).map!standardDeviation.all!approxEqual(m0)); auto m1 = [1.0, 1.0]; assert(x.alongDim!1.map!standardDeviation.all!approxEqual(m1)); assert(x.alongDim!(-1).map!standardDeviation.all!approxEqual(m1)); assert(iota(2, 3, 4, 5).as!double.alongDim!0.map!standardDeviation.all!approxEqual(repeat(sqrt(3600.0 / 2), 3, 4, 5)));
Arbitrary standard deviation
import mir.math.common: sqrt; assert(standardDeviation(1.0, 2, 3) == 1.0); assert(standardDeviation!float(1, 2, 3) == 1f);
Calculates the standard deviation of the input
By default, if F is not floating point type, then the result will have a double type if F is implicitly convertible to a floating point type.