function that will produce the value that the input is centered about, default is mean
function to transform centered values, default squares the centered values
function to summarize the transformed centered values, default is mean
The dispersion of the input
Simple examples
import mir.complex: Complex; import mir.complex.math: capproxEqual = approxEqual; import mir.functional: naryFun; import mir.math.common: approxEqual; import mir.ndslice.slice: sliced; alias C = Complex!double; assert(dispersion([1.0, 2, 3]).approxEqual(2.0 / 3)); assert(dispersion([C(1.0, 3), C(2), C(3)]).capproxEqual(C(-4, -6) / 3)); assert(dispersion!(mean!float, "a * a", mean!float)([0, 1, 2, 3, 4, 5].sliced(3, 2)).approxEqual(17.5 / 6)); static assert(is(typeof(dispersion!(mean!float, "a ^^ 2", mean!float)([1, 2, 3])) == float));
Dispersion of vector
import mir.math.common: approxEqual; 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]; assert(x.dispersion.approxEqual(54.76562 / 12));
Dispersion of matrix
import mir.math.common: approxEqual; 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.dispersion.approxEqual(54.76562 / 12));
Column dispersion of matrix
import mir.algorithm.iteration: all; import mir.math.common: approxEqual; 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 / 3, 7.041667 / 3, 0.1666667 / 3, 30.16667 / 3]; // Use byDim or alongDim with map to compute dispersion of row/column. assert(x.byDim!1.map!dispersion.all!approxEqual(result)); assert(x.alongDim!0.map!dispersion.all!approxEqual(result)); // FIXME // Without using map, computes the dispersion of the whole slice // assert(x.byDim!1.dispersion == x.sliced.dispersion); // assert(x.alongDim!0.dispersion == x.sliced.dispersion);
Can also set functions to change type of dispersion that is used
import mir.functional: naryFun; import mir.math.common: approxEqual, fabs, sqrt; 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]; alias square = naryFun!"a * a"; // Other population variance examples assert(x.dispersion.approxEqual(54.76562 / 12)); assert(x.dispersion!mean.approxEqual(54.76562 / 12)); assert(x.dispersion!(mean, square).approxEqual(54.76562 / 12)); assert(x.dispersion!(mean, square, mean).approxEqual(54.76562 / 12)); // Population standard deviation assert(x.dispersion!(mean, square, mean).sqrt.approxEqual(sqrt(54.76562 / 12))); // Mean absolute deviation about the mean assert(x.dispersion!(mean, fabs, mean).approxEqual(21.0 / 12)); //Mean absolute deviation about the median assert(x.dispersion!(median, fabs, mean).approxEqual(19.25000 / 12)); //Median absolute deviation about the mean assert(x.dispersion!(mean, fabs, median).approxEqual(1.43750)); //Median absolute deviation about the median assert(x.dispersion!(median, fabs, median).approxEqual(1.25000));
For integral slices, pass output type to centralTendency, transform, and summary functions as template parameter to ensure output type is correct.
import mir.functional: naryFun; import mir.math.common: approxEqual; import mir.ndslice.slice: sliced; auto x = [0, 1, 1, 2, 4, 4, 2, 7, 5, 1, 2, 0].sliced; alias square = naryFun!"a * a"; auto y = x.dispersion; assert(y.approxEqual(50.91667 / 12)); static assert(is(typeof(y) == double)); assert(x.dispersion!(mean!float, square, mean!float).approxEqual(50.91667 / 12));
Dispersion works for complex numbers and other user-defined types (provided that the centralTendency, transform, and summary functions are defined for those types)
import mir.ndslice.slice: sliced; import std.complex: Complex; import std.math.operations: isClose; auto x = [Complex!double(1, 2), Complex!double(2, 3), Complex!double(3, 4), Complex!double(4, 5)].sliced; assert(x.dispersion.isClose(Complex!double(0, 10) / 4));
Compute mean tensors along specified dimention of tensors
import mir.algorithm.iteration: all; import mir.math.common: approxEqual; 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.dispersion.approxEqual(17.5 / 6)); auto m0 = [2.25, 2.25, 2.25]; assert(x.alongDim!0.map!dispersion.all!approxEqual(m0)); assert(x.alongDim!(-2).map!dispersion.all!approxEqual(m0)); auto m1 = [2.0 / 3, 2.0 / 3]; assert(x.alongDim!1.map!dispersion.all!approxEqual(m1)); assert(x.alongDim!(-1).map!dispersion.all!approxEqual(m1)); assert(iota(2, 3, 4, 5).as!double.alongDim!0.map!dispersion.all!approxEqual(repeat(1800.0 / 2, 3, 4, 5)));
Arbitrary dispersion
import mir.functional: naryFun; import mir.math.common: approxEqual; alias square = naryFun!"a * a"; assert(dispersion(1.0, 2, 3).approxEqual(2.0 / 3)); assert(dispersion!(mean!float, square, mean!float)(1, 2, 3).approxEqual(2f / 3));
Calculates the dispersion of the input.
For an input x, this function first centers x by subtracting each e in x by the result of centralTendency, then it transforms the centered values using the function transform, and then finally summarizes that information using the summarize funcion.
The default functions provided are equivalent to calculating the population variance. The centralTendency default is the mean function, which results in the input being centered about the mean. The default transform function will square the centered values. The default summarize function is mean, which will return the mean of the squared centered values.