controls n-th standardized moment
algorithm for calculating sums (default: Summation.appropriate)
The n-th standardized moment of the input, must be floating point
Basic implementation
import mir.math.common: approxEqual; import mir.ndslice.slice: sliced; assert(standardizedMoment!1([1.0, 2, 3]).approxEqual(0.0)); assert(standardizedMoment!2([1.0, 2, 3]).approxEqual(1.0)); assert(standardizedMoment!3([1.0, 2, 3]).approxEqual(0.0 / 3)); assert(standardizedMoment!4([1.0, 2, 3]).approxEqual(4.5 / 3)); assert(standardizedMoment!(float, 2)([0, 1, 2, 3, 4, 5].sliced(3, 2)).approxEqual(6f / 6)); static assert(is(typeof(standardizedMoment!(float, 2)([1, 2, 3])) == float));
Standardized Moment of vector
import mir.math.common: approxEqual; 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.standardizedMoment!3.approxEqual(12.000999 / 12));
Standardized Moment 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.standardizedMoment!3.approxEqual(12.000999 / 12));
Can also set algorithm type
import mir.math.common: approxEqual; 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 + 100_000_000_000; // The default algorithm is numerically stable in this case auto y = x.standardizedMoment!3; assert(y.approxEqual(12.000999 / 12)); // The online algorithm is numerically unstable in this case auto z1 = x.standardizedMoment!(3, "scaled", "online"); assert(!z1.approxEqual(12.000999 / 12)); assert(!z1.approxEqual(y)); // It is also numerically unstable when using StandardizedMomentAlgo.centered auto z2 = x.standardizedMoment!(3, "centered", "online"); assert(!z2.approxEqual(12.000999 / 12)); assert(!z2.approxEqual(y));
Can also set algorithm or output type
import mir.math.common: approxEqual; import mir.ndslice.slice: sliced; //Set standardized moment algorithm, variance algorithm, sum algorithm, or output type auto a = [1.0, 1e98, 1, -1e98].sliced; auto x = a * 10_000; /++ 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.standardizedMoment!3.approxEqual(0.0)); assert(x.standardizedMoment!(3, "scaled", "online").approxEqual(0.0)); assert(x.standardizedMoment!(3, "centered", "online").approxEqual(0.0)); assert(x.standardizedMoment!(3, "scaled", "online", "kbn").approxEqual(0.0)); assert(x.standardizedMoment!(3, "scaled", "online", "kb2").approxEqual(0.0)); assert(x.standardizedMoment!(3, "scaled", "online", "precise").approxEqual(0.0)); assert(x.standardizedMoment!(double, 3, "scaled", "online", "precise").approxEqual(0.0)); auto y = [uint.max - 2, uint.max - 1, uint.max].sliced; auto z = y.standardizedMoment!(ulong, 3); assert(z == 0.0); static assert(is(typeof(z) == double));
For integral slices, can pass output type as template parameter to ensure output type is correct. By default, they get converted to double.
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; auto y = x.standardizedMoment!3; assert(y.approxEqual(9.666455 / 12)); static assert(is(typeof(y) == double)); assert(x.standardizedMoment!(float, 3).approxEqual(9.666455f / 12));
Arbitrary standardized moment
import mir.math.common: approxEqual; assert(standardizedMoment!3(1.0, 2, 3).approxEqual(0.0 / 3)); assert(standardizedMoment!(float, 3)(1, 2, 3).approxEqual(0f / 3)); assert(standardizedMoment!(float, 3, "centered")(1, 2, 3).approxEqual(0f / 3));
Calculates the n-th standardized moment 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.