The OpenD Programming Language

quantile

Examples

Simple example

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [3.0, 1.0, 4.0, 2.0, 0.0].sliced;

assert(x.quantile(0.5).approxEqual(2.0));

auto qtile = [0.25, 0.75].sliced;

assert(x.quantile(qtile).all!approxEqual([1.0, 3.0]));
assert(x.quantile(0.25, 0.75).all!approxEqual([1.0, 3.0]));

Modify probability in place

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [3.0, 1.0, 4.0, 2.0, 0.0].sliced;

auto qtile = [0.25, 0.75].sliced;
auto qtile_copy = qtile.dup;

x.quantile!("type7", false, true)(qtile);
assert(qtile.all!approxEqual([1.0, 3.0]));
assert(!qtile.all!approxEqual(qtile_copy));

Quantile of vector

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [1.0, 9.8, 0.2, 8.5, 5.8, 3.5, 4.5, 8.2, 5.2, 5.2,
          2.5, 1.8, 2.2, 3.8, 5.2, 9.2, 6.2, 9.2, 9.2, 8.5].sliced;

assert(x.quantile(0.5).approxEqual(5.20));

auto qtile = [0.25, 0.75].sliced;

assert(x.quantile(qtile).all!approxEqual([3.250, 8.500]));

Quantile of matrix

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;
import mir.ndslice.slice: sliced;

auto x = [
    [1.0, 9.8, 0.2, 8.5, 5.8, 3.5, 4.5, 8.2, 5.2, 5.2],
    [2.5, 1.8, 2.2, 3.8, 5.2, 9.2, 6.2, 9.2, 9.2, 8.5]
].fuse;

assert(x.quantile(0.5).approxEqual(5.20));

auto qtile = [0.25, 0.75].sliced;

assert(x.quantile(qtile).all!approxEqual([3.250, 8.500]));

Row quantile of matrix

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.fuse: fuse;
import mir.ndslice.slice: sliced;
import mir.ndslice.topology: alongDim, byDim, map, flattened;

auto x = [
    [1.0, 9.8, 0.2, 8.5, 5.8, 3.5, 4.5, 8.2, 5.2, 5.2],
    [2.5, 1.8, 2.2, 3.8, 5.2, 9.2, 6.2, 9.2, 9.2, 8.5]
].fuse;

auto result0 = [5.200, 5.700];

// Use byDim or alongDim with map to compute median of row/column.
assert(x.byDim!0.map!(a => a.quantile(0.5)).all!approxEqual(result0));
assert(x.alongDim!1.map!(a => a.quantile(0.5)).all!approxEqual(result0));

auto qtile = [0.25, 0.75].sliced;
auto result1 = [[3.750, 7.600], [2.825, 9.025]];

assert(x.byDim!0.map!(a => a.quantile(qtile)).all!(all!approxEqual)(result1));

Allow modification of input

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [3.0, 1.0, 4.0, 2.0, 0.0].sliced;
auto x_copy = x.dup;

auto result = x.quantile!(QuantileAlgo.type7, true)(0.5);
assert(!x.all!approxEqual(x_copy));

Double-check probability is not modified

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [3.0, 1.0, 4.0, 2.0, 0.0].sliced;

auto qtile = [0.25, 0.75].sliced;
auto qtile_copy = qtile.dup;

auto result = x.quantile!("type7", false, false)(qtile);
assert(result.all!approxEqual([1.0, 3.0]));
assert(qtile.all!approxEqual(qtile_copy));

Can also set algorithm type

import mir.math.common: approxEqual;
import mir.ndslice.slice: sliced;

auto x = [1.0, 9.8, 0.2, 8.5, 5.8, 3.5, 4.5, 8.2, 5.2, 5.2,
          2.5, 1.8, 2.2, 3.8, 5.2, 9.2, 6.2, 9.2, 9.2, 8.5].sliced;

assert(x.quantile!"type1"(0.5).approxEqual(5.20));
assert(x.quantile!"type2"(0.5).approxEqual(5.20));
assert(x.quantile!"type3"(0.5).approxEqual(5.20));
assert(x.quantile!"type4"(0.5).approxEqual(5.20));
assert(x.quantile!"type5"(0.5).approxEqual(5.20));
assert(x.quantile!"type6"(0.5).approxEqual(5.20));
assert(x.quantile!"type7"(0.5).approxEqual(5.20));
assert(x.quantile!"type8"(0.5).approxEqual(5.20));
assert(x.quantile!"type9"(0.5).approxEqual(5.20));

Can also set algorithm or output type

import mir.ndslice.slice: sliced;

auto a = [1, 1e100, 1, -1e100].sliced;

auto x = a * 10_000;

auto result0 = x.quantile!float(0.5);
assert(result0 == 10_000f);
static assert(is(typeof(result0) == float));

auto result1 = x.quantile!(float, "type8")(0.5);
assert(result1 == 10_000f);
static assert(is(typeof(result1) == float));

Support for integral and user-defined types for type 1 & 3

import mir.ndslice.topology: repeat;

auto x = uint.max.repeat(3);
assert(x.quantile!(uint, "type1")(0.5) == uint.max);
assert(x.quantile!(uint, "type3")(0.5) == uint.max);

static struct Foo {
    float x;
    alias x this;
}

Foo[] foo = [Foo(1f), Foo(2f), Foo(3f)];
assert(foo.quantile!"type1"(0.5) == 2f);
assert(foo.quantile!"type3"(0.5) == 2f);

Compute quantile 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, 3],
    [4.0, 5, 7]
].fuse;

assert(x.quantile(0.5).approxEqual(3.5));

auto m0 = [2.0, 3.0, 5.0];
assert(x.alongDim!0.map!(a => a.quantile(0.5)).all!approxEqual(m0));
assert(x.alongDim!(-2).map!(a => a.quantile(0.5)).all!approxEqual(m0));

auto m1 = [1.0, 5.0];
assert(x.alongDim!1.map!(a => a.quantile(0.5)).all!approxEqual(m1));
assert(x.alongDim!(-1).map!(a => a.quantile(0.5)).all!approxEqual(m1));

assert(iota(2, 3, 4, 5).as!double.alongDim!0.map!(a => a.quantile(0.5)).all!approxEqual(iota([3, 4, 5], 3 * 4 * 5 / 2)));

Support for array

import mir.algorithm.iteration: all;
import mir.math.common: approxEqual;

double[] x = [3.0, 1.0, 4.0, 2.0, 0.0];

assert(x.quantile(0.5).approxEqual(2.0));

double[] qtile = [0.25, 0.75];

assert(x.quantile(qtile).all!approxEqual([1.0, 3.0]));

Meta