The OpenD Programming Language

standardizedMoment

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.

Parameters

N

controls n-th standardized moment

summation

algorithm for calculating sums (default: Summation.appropriate)

Return Value

The n-th standardized moment of the input, must be floating point

Examples

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));

Meta