blob: 6dcb635d2124ac5e2d59e1610daf32a2fba6a84a [file] [log] [blame]
"use strict";
var assert = require('assert');
var Statistics = require('../public/shared/statistics.js');
if (!assert.almostEqual)
assert.almostEqual = require('./resources/almost-equal.js');
describe('assert.almostEqual', function () {
it('should not throw when values are identical', function () {
assert.doesNotThrow(function () { assert.almostEqual(1, 1); });
});
it('should not throw when values are close', function () {
assert.doesNotThrow(function () { assert.almostEqual(1.10, 1.107, 2); });
assert.doesNotThrow(function () { assert.almostEqual(1256.7, 1256.72, 4); });
});
it('should throw when values are not close', function () {
assert.throws(function () { assert.almostEqual(1.10, 1.27, 2); });
assert.throws(function () { assert.almostEqual(735.4, 735.6, 4); });
});
});
describe('Statistics', function () {
describe('min', function () {
it('should find the mininum value', function () {
assert.equal(Statistics.min([1, 2, 3, 4]), 1);
assert.equal(Statistics.min([4, 3, 2, 1]), 1);
assert.equal(Statistics.min([2000, 20, 200]), 20);
assert.equal(Statistics.min([0.3, 0.06, 0.5]), 0.06);
assert.equal(Statistics.min([-0.3, 0.06, 0.5]), -0.3);
assert.equal(Statistics.min([-0.3, 0.06, 0.5, Infinity]), -0.3);
assert.equal(Statistics.min([-0.3, 0.06, 0.5, -Infinity]), -Infinity);
assert.equal(Statistics.min([]), Infinity);
});
});
describe('max', function () {
it('should find the mininum value', function () {
assert.equal(Statistics.max([1, 2, 3, 4]), 4);
assert.equal(Statistics.max([4, 3, 2, 1]), 4);
assert.equal(Statistics.max([2000, 20, 200]), 2000);
assert.equal(Statistics.max([0.3, 0.06, 0.5]), 0.5);
assert.equal(Statistics.max([-0.3, 0.06, 0.5]), 0.5);
assert.equal(Statistics.max([-0.3, 0.06, 0.5, Infinity]), Infinity);
assert.equal(Statistics.max([-0.3, 0.06, 0.5, -Infinity]), 0.5);
assert.equal(Statistics.max([]), -Infinity);
});
});
describe('sum', function () {
it('should find the sum of values', function () {
assert.equal(Statistics.sum([1, 2, 3, 4]), 10);
assert.equal(Statistics.sum([4, 3, 2, 1]), 10);
assert.equal(Statistics.sum([2000, 20, 200]), 2220);
assert.equal(Statistics.sum([0.3, 0.06, 0.5]), 0.86);
assert.equal(Statistics.sum([-0.3, 0.06, 0.5]), 0.26);
assert.equal(Statistics.sum([-0.3, 0.06, 0.5, Infinity]), Infinity);
assert.equal(Statistics.sum([-0.3, 0.06, 0.5, -Infinity]), -Infinity);
assert.equal(Statistics.sum([]), 0);
});
});
describe('weightedMean',() => {
it('should return mean with weight', () => {
assert.equal(Statistics.weightedMean([{value: 1, weight: 1}, {value: 2, weight: 2},
{value: 3, weight: 3}, {value: 4, weight: 4}]), 3);
assert.equal(Statistics.weightedMean([{value: 1, weight: 1}, {value: 2, weight: 0},
{value: 3, weight: 0}, {value: 4, weight: 0}]), 1);
});
});
describe('squareSum', function () {
it('should find the square sum of values', function () {
assert.equal(Statistics.squareSum([1, 2, 3, 4]), 30);
assert.equal(Statistics.squareSum([4, 3, 2, 1]), 30);
assert.equal(Statistics.squareSum([2000, 20, 200]), 2000 * 2000 + 20 * 20 + 200* 200);
assert.equal(Statistics.squareSum([0.3, 0.06, 0.5]), 0.09 + 0.0036 + 0.25);
assert.equal(Statistics.squareSum([-0.3, 0.06, 0.5]), 0.09 + 0.0036 + 0.25);
assert.equal(Statistics.squareSum([-0.3, 0.06, 0.5, Infinity]), Infinity);
assert.equal(Statistics.squareSum([-0.3, 0.06, 0.5, -Infinity]), Infinity);
assert.equal(Statistics.squareSum([]), 0);
});
});
describe('sampleStandardDeviation', function () {
function stdev(values) {
return Statistics.sampleStandardDeviation(values.length,
Statistics.sum(values), Statistics.squareSum(values));
}
it('should find the standard deviation of values', function () {
assert.almostEqual(stdev([1, 2, 3, 4]), 1.2909944);
assert.almostEqual(stdev([4, 3, 2, 1]), 1.2909944);
assert.almostEqual(stdev([2000, 20, 200]), 1094.89726);
assert.almostEqual(stdev([0.3, 0.06, 0.5]), 0.220302822);
assert.almostEqual(stdev([-0.3, 0.06, 0.5]), 0.40066611203);
assert.almostEqual(stdev([-0.3, 0.06, 0.5, Infinity]), NaN);
assert.almostEqual(stdev([-0.3, 0.06, 0.5, -Infinity]), NaN);
assert.almostEqual(stdev([]), 0);
});
});
describe('confidenceIntervalDelta', function () {
it('should find the p-value of values using Student\'s t distribution', function () {
function delta(values, probabilty) {
return Statistics.confidenceIntervalDelta(probabilty, values.length,
Statistics.sum(values), Statistics.squareSum(values));
}
// https://onlinecourses.science.psu.edu/stat414/node/199
var values = [118, 115, 125, 110, 112, 130, 117, 112, 115, 120, 113, 118, 119, 122, 123, 126];
assert.almostEqual(delta(values, 0.95), 3.015, 3);
// Following values are computed using Excel Online's STDEV and CONFIDENCE.T
assert.almostEqual(delta([1, 2, 3, 4], 0.8), 1.057159, 4);
assert.almostEqual(delta([1, 2, 3, 4], 0.9), 1.519090, 4);
assert.almostEqual(delta([1, 2, 3, 4], 0.95), 2.054260, 4);
assert.almostEqual(delta([0.3, 0.06, 0.5], 0.8), 0.2398353, 4);
assert.almostEqual(delta([0.3, 0.06, 0.5], 0.9), 0.3713985, 4);
assert.almostEqual(delta([0.3, 0.06, 0.5], 0.95), 0.5472625, 4);
assert.almostEqual(delta([-0.3, 0.06, 0.5], 0.8), 0.4361900, 4);
assert.almostEqual(delta([-0.3, 0.06, 0.5], 0.9), 0.6754647, 4);
assert.almostEqual(delta([-0.3, 0.06, 0.5], 0.95), 0.9953098, 4);
assert.almostEqual(delta([123, 107, 109, 104, 111], 0.8), 5.001167, 4);
assert.almostEqual(delta([123, 107, 109, 104, 111], 0.9), 6.953874, 4);
assert.almostEqual(delta([123, 107, 109, 104, 111], 0.95), 9.056490, 4);
assert.almostEqual(delta([6785, 7812, 6904, 7503, 6943, 7207, 6812], 0.8), 212.6155, 4);
assert.almostEqual(delta([6785, 7812, 6904, 7503, 6943, 7207, 6812], 0.9), 286.9585, 4);
assert.almostEqual(delta([6785, 7812, 6904, 7503, 6943, 7207, 6812], 0.95), 361.3469, 4);
});
});
// https://en.wikipedia.org/wiki/Welch%27s_t_test
var example1 = {
A1: [27.5, 21.0, 19.0, 23.6, 17.0, 17.9, 16.9, 20.1, 21.9, 22.6, 23.1, 19.6, 19.0, 21.7, 21.4],
A2: [27.1, 22.0, 20.8, 23.4, 23.4, 23.5, 25.8, 22.0, 24.8, 20.2, 21.9, 22.1, 22.9, 20.5, 24.4],
expectedT: 2.46,
expectedDegreesOfFreedom: 25.0,
expectedRange: [0.95, 0.98] // P = 0.021 so 1 - P = 0.979 is between 0.95 and 0.98
};
var example2 = {
A1: [17.2, 20.9, 22.6, 18.1, 21.7, 21.4, 23.5, 24.2, 14.7, 21.8],
A2: [21.5, 22.8, 21.0, 23.0, 21.6, 23.6, 22.5, 20.7, 23.4, 21.8, 20.7, 21.7, 21.5, 22.5, 23.6, 21.5, 22.5, 23.5, 21.5, 21.8],
expectedT: 1.57,
expectedDegreesOfFreedom: 9.9,
expectedRange: [0.8, 0.9] // P = 0.149 so 1 - P = 0.851 is between 0.8 and 0.9
};
var example3 = {
A1: [19.8, 20.4, 19.6, 17.8, 18.5, 18.9, 18.3, 18.9, 19.5, 22.0],
A2: [28.2, 26.6, 20.1, 23.3, 25.2, 22.1, 17.7, 27.6, 20.6, 13.7, 23.2, 17.5, 20.6, 18.0, 23.9, 21.6, 24.3, 20.4, 24.0, 13.2],
expectedT: 2.22,
expectedDegreesOfFreedom: 24.5,
expectedRange: [0.95, 0.98] // P = 0.036 so 1 - P = 0.964 is beteween 0.95 and 0.98
};
describe('computeWelchsT', function () {
function computeWelchsT(values1, values2, probability) {
return Statistics.computeWelchsT(values1, 0, values1.length, values2, 0, values2.length, probability);
}
it('should detect the statistically significant difference using Welch\'s t-test', function () {
assert.equal(computeWelchsT(example1.A1, example1.A2, 0.8).significantlyDifferent, true);
assert.equal(computeWelchsT(example1.A1, example1.A2, 0.9).significantlyDifferent, true);
assert.equal(computeWelchsT(example1.A1, example1.A2, 0.95).significantlyDifferent, true);
assert.equal(computeWelchsT(example1.A1, example1.A2, 0.98).significantlyDifferent, false);
assert.equal(computeWelchsT(example2.A1, example2.A2, 0.8).significantlyDifferent, true);
assert.equal(computeWelchsT(example2.A1, example2.A2, 0.9).significantlyDifferent, false);
assert.equal(computeWelchsT(example2.A1, example2.A2, 0.95).significantlyDifferent, false);
assert.equal(computeWelchsT(example2.A1, example2.A2, 0.98).significantlyDifferent, false);
assert.equal(computeWelchsT(example3.A1, example3.A2, 0.8).significantlyDifferent, true);
assert.equal(computeWelchsT(example3.A1, example3.A2, 0.9).significantlyDifferent, true);
assert.equal(computeWelchsT(example3.A1, example3.A2, 0.95).significantlyDifferent, true);
assert.equal(computeWelchsT(example3.A1, example3.A2, 0.98).significantlyDifferent, false);
});
it('should find the t-value of values using Welch\'s t-test', function () {
assert.almostEqual(computeWelchsT(example1.A1, example1.A2).t, example1.expectedT, 2);
assert.almostEqual(computeWelchsT(example2.A1, example2.A2).t, example2.expectedT, 2);
assert.almostEqual(computeWelchsT(example3.A1, example3.A2).t, example3.expectedT, 2);
});
it('should find the degreees of freedom using Welch–Satterthwaite equation', function () {
assert.almostEqual(computeWelchsT(example1.A1, example1.A2).degreesOfFreedom, example1.expectedDegreesOfFreedom, 2);
assert.almostEqual(computeWelchsT(example2.A1, example2.A2).degreesOfFreedom, example2.expectedDegreesOfFreedom, 2);
assert.almostEqual(computeWelchsT(example3.A1, example3.A2).degreesOfFreedom, example3.expectedDegreesOfFreedom, 2);
});
it('should respect the start and the end indices', function () {
var A1 = example2.A1.slice();
var A2 = example2.A2.slice();
var expectedT = Statistics.computeWelchsT(A1, 0, A1.length, A2, 0, A2.length).t;
A1.unshift(21);
A1.push(15);
A1.push(24);
assert.almostEqual(Statistics.computeWelchsT(A1, 1, A1.length - 3, A2, 0, A2.length).t, expectedT);
A2.unshift(24.3);
A2.unshift(25.8);
A2.push(23);
A2.push(24);
A2 = A2.reverse();
assert.almostEqual(Statistics.computeWelchsT(A1, 1, A1.length - 3, A2, 2, A2.length - 4).t, expectedT);
});
});
describe('probabilityRangeForWelchsT', function () {
it('should find the t-value of values using Welch\'s t-test', function () {
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).t, example1.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).t, example2.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).t, example3.expectedT, 2);
});
it('should find the degreees of freedom using Welch–Satterthwaite equation', function () {
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).degreesOfFreedom,
example1.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).degreesOfFreedom,
example2.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).degreesOfFreedom,
example3.expectedDegreesOfFreedom, 2);
});
it('should compute the range of probabilites using the p-value of Welch\'s t-test', function () {
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).range[0], example1.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example1.A1, example1.A2).range[1], example1.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).range[0], example2.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example2.A1, example2.A2).range[1], example2.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).range[0], example3.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsT(example3.A1, example3.A2).range[1], example3.expectedRange[1]);
});
});
describe('minimumTForOneSidedProbability', () => {
it('should not infinite loop when lookup t-value for any degrees of freedom', () => {
for(const probability of [0.9, 0.95, 0.975, 0.99]) {
for (let degreesOfFreedom = 1; degreesOfFreedom < 100000; degreesOfFreedom += 1)
Statistics.minimumTForOneSidedProbability(probability, degreesOfFreedom);
}
})
});
describe('probabilityRangeForWelchsTForMultipleSamples', () => {
function splitSample(samples) {
const mid = samples.length / 2;
return splitSampleByIndices(samples, mid);
}
function splitSampleByIndices(samples, ...indices) {
const sampleSize = samples.length;
const splittedSamples = [];
let previousIndex = 0;
for (const index of indices) {
if (index == previousIndex)
continue;
console.assert(index > previousIndex);
console.assert(index <= sampleSize);
splittedSamples.push(samples.slice(previousIndex, index));
previousIndex = index;
}
if (previousIndex < sampleSize)
splittedSamples.push(samples.slice(previousIndex, sampleSize));
return splittedSamples.map((values) => ({sum: Statistics.sum(values), squareSum: Statistics.squareSum(values), sampleSize: values.length}));
}
it('should find the t-value of values using Welch\'s t-test', () => {
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).t, example1.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).t, example2.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).t, example3.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).t, example1.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).t, example2.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).t, example3.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).t, example1.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).t, example2.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).t, example3.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).t, example1.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).t, example2.expectedT, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).t, example3.expectedT, 2);
});
it('should find the degreees of freedom using Welch–Satterthwaite equation when split evenly', () => {
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).degreesOfFreedom,
example1.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).degreesOfFreedom,
example2.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).degreesOfFreedom,
example3.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).degreesOfFreedom,
example1.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).degreesOfFreedom,
example2.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).degreesOfFreedom,
example3.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).degreesOfFreedom,
example1.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).degreesOfFreedom,
example2.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).degreesOfFreedom,
example3.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).degreesOfFreedom,
example1.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).degreesOfFreedom,
example2.expectedDegreesOfFreedom, 2);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).degreesOfFreedom,
example3.expectedDegreesOfFreedom, 2);
});
it('should compute the range of probabilites using the p-value of Welch\'s t-test when split evenly', function () {
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).range[0], example1.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example1.A1), splitSample(example1.A2)).range[1], example1.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).range[0], example2.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example2.A1), splitSample(example2.A2)).range[1], example2.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).range[0], example3.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSample(example3.A1), splitSample(example3.A2)).range[1], example3.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).range[0], example1.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1), splitSampleByIndices(example1.A2, 1)).range[1], example1.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).range[0], example2.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1), splitSampleByIndices(example2.A2, 1)).range[1], example2.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).range[0], example3.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1), splitSampleByIndices(example3.A2, 1)).range[1], example3.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).range[0], example1.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 0), splitSampleByIndices(example1.A2, 0)).range[1], example1.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).range[0], example2.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 0), splitSampleByIndices(example2.A2, 0)).range[1], example2.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).range[0], example3.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 0), splitSampleByIndices(example3.A2, 0)).range[1], example3.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).range[0], example1.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example1.A1, 1, 4), splitSampleByIndices(example1.A2, 1, 4)).range[1], example1.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).range[0], example2.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example2.A1, 1, 4), splitSampleByIndices(example2.A2, 1, 4)).range[1], example2.expectedRange[1]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).range[0], example3.expectedRange[0]);
assert.almostEqual(Statistics.probabilityRangeForWelchsTForMultipleSamples(splitSampleByIndices(example3.A1, 1, 4), splitSampleByIndices(example3.A2, 1, 4)).range[1], example3.expectedRange[1]);
});
});
describe('movingAverage', function () {
it('should return the origian values when both forward and backward window size is 0', function () {
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 0), [1, 2, 3, 4, 5]);
});
it('should find the moving average with a positive backward window', function () {
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 1, 0),
[1, (1 + 2) / 2, (2 + 3) / 2, (3 + 4) / 2, (4 + 5) / 2]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 0),
[1, (1 + 2) / 2, (1 + 2 + 3) / 3, (2 + 3 + 4) / 3, (3 + 4 + 5) / 3]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 3, 0),
[1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 4, 0),
[1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 5, 0),
[1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5]);
});
it('should find the moving average with a positive forward window', function () {
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 1),
[(1 + 2) / 2, (2 + 3) / 2, (3 + 4) / 2, (4 + 5) / 2, 5]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 2),
[(1 + 2 + 3) / 3, (2 + 3 + 4) / 3, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 3),
[(1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 4),
[(1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 0, 5),
[(1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2, 5]);
});
it('should find the moving average when both backward and forward window sizes are specified', function () {
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 1, 1),
[(1 + 2) / 2, (1 + 2 + 3) / 3, (2 + 3 + 4) / 3, (3 + 4 + 5) / 3, (4 + 5) / 2]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 1, 2),
[(1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3, (4 + 5) / 2]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 1),
[(1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 2),
[(1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 2, 3),
[(1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4, (3 + 4 + 5) / 3]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 3, 2),
[(1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4]);
assert.deepEqual(Statistics.movingAverage([1, 2, 3, 4, 5], 3, 3),
[(1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (1 + 2 + 3 + 4 + 5) / 5, (2 + 3 + 4 + 5) / 4]);
});
});
describe('cumulativeMovingAverage', function () {
it('should find the cumulative moving average', function () {
assert.deepEqual(Statistics.cumulativeMovingAverage([1, 2, 3, 4, 5]),
[1, (1 + 2) / 2, (1 + 2 + 3) / 3, (1 + 2 + 3 + 4) / 4, (1 + 2 + 3 + 4 + 5) / 5]);
assert.deepEqual(Statistics.cumulativeMovingAverage([-1, 7, 0, 8.5, 2]),
[-1, (-1 + 7) / 2, (-1 + 7 + 0) / 3, (-1 + 7 + 0 + 8.5) / 4, (-1 + 7 + 0 + 8.5 + 2) / 5]);
});
});
describe('exponentialMovingAverage', function () {
it('should find the exponential moving average', function () {
var averages = Statistics.exponentialMovingAverage([1, 2, 3, 4, 5], 0.2);
assert.equal(averages[0], 1);
assert.almostEqual(averages[1], 0.2 * 2 + 0.8 * averages[0]);
assert.almostEqual(averages[2], 0.2 * 3 + 0.8 * averages[1]);
assert.almostEqual(averages[3], 0.2 * 4 + 0.8 * averages[2]);
assert.almostEqual(averages[4], 0.2 * 5 + 0.8 * averages[3]);
averages = Statistics.exponentialMovingAverage([0.8, -0.2, 0.4, -0.3, 0.5], 0.1);
assert.almostEqual(averages[0], 0.8);
assert.almostEqual(averages[1], 0.1 * -0.2 + 0.9 * averages[0]);
assert.almostEqual(averages[2], 0.1 * 0.4 + 0.9 * averages[1]);
assert.almostEqual(averages[3], 0.1 * -0.3 + 0.9 * averages[2]);
assert.almostEqual(averages[4], 0.1 * 0.5 + 0.9 * averages[3]);
});
});
describe('segmentTimeSeriesGreedyWithStudentsTTest', function () {
it('should segment time series', function () {
assert.deepEqual(Statistics.segmentTimeSeriesGreedyWithStudentsTTest([1, 1, 1, 3, 3, 3], 1), [0, 2, 6]);
assert.deepEqual(Statistics.segmentTimeSeriesGreedyWithStudentsTTest([1, 1.2, 0.9, 1.1, 1.5, 1.7, 1.8], 1), [0, 4, 7]);
});
});
describe('segmentTimeSeriesByMaximizingSchwarzCriterion', function () {
it('should segment time series of length 0 into a single segment', function () {
var values = [];
assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 0]);
});
it('should not segment time series of length two into two pieces', function () {
var values = [1, 2];
assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 2]);
});
it('should segment time series [1, 2, 3] into three pieces', function () {
var values = [1, 2, 3];
assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 1, 3]);
});
it('should segment time series for platform=47 metric=4875 between 1453938553772 and 1454630903100 into two parts', function () {
var values = [
1546.5603, 1548.1536, 1563.5452, 1539.7823, 1546.4184, 1548.9299, 1532.5444, 1546.2800, 1547.1760, 1551.3507,
1548.3277, 1544.7673, 1542.7157, 1538.1700, 1538.0948, 1543.0364, 1537.9737, 1542.2611, 1543.9685, 1546.4901,
1544.4080, 1540.8671, 1537.3353, 1549.4331, 1541.4436, 1544.1299, 1550.1770, 1553.1872, 1549.3417, 1542.3788,
1543.5094, 1541.7905, 1537.6625, 1547.3840, 1538.5185, 1549.6764, 1556.6138, 1552.0476, 1541.7629, 1544.7006,
/* segments changes here */
1587.1390, 1594.5451, 1586.2430, 1596.7310, 1548.1423];
assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 39, values.length]);
});
it('should segment time series for platform=51 metric=4565 betweeen 1452191332230 and 1454628206453 into two parts', function () {
var values = [
147243216, 147736350, 146670090, 146629723, 142749220, 148234161, 147303822, 145112097, 145852468, 147094741,
147568897, 145160531, 148028242, 141272279, 144323236, 147492567, 146219156, 144895726, 144418925, 145455873,
141924694, 141025833, 142082139, 144154698, 145312939, 148282554, 151852126, 149303740, 149431703, 150300257,
148752468, 150449779, 150030118, 150553542, 151775421, 146666762, 149492535, 147143284, 150356837, 147799616,
149889520,
258634751, 147397840, 256106147, 261100534, 255903392, 259658019, 259501433, 257685682, 258460322, 255563633,
259050663, 255567490, 253274911];
assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, 40, values.length]);
});
it('should not segment time series for platform=51 metric=4817 betweeen 1453926047749 and 1454635479052 into multiple parts', function () {
var values = [
5761.3, 5729.4, 5733.49, 5727.4, 5726.56, 5727.48, 5716.79, 5721.23, 5682.5, 5735.71,
5750.99, 5755.51, 5756.02, 5725.76, 5710.14, 5776.17, 5774.29, 5769.99, 5739.65, 5756.05,
5722.87, 5726.8, 5779.23, 5772.2, 5763.1, 5807.05];
assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [0, values.length]);
});
it('should not segment time series for platform=51 metric=4817 betweeen 1453926047749 and 1454635479052 into multiple parts', function () {
var values = new Array(37);
for (let i = 0; i < 37; i++)
values[i] = 1;
assert.deepEqual(Statistics.segmentTimeSeriesByMaximizingSchwarzCriterion(values), [ 0, 6, 16, 26, 37 ]);
});
});
describe('findRangesForChangeDetectionsWithWelchsTTest', () => {
it('should return an empty array if the value is empty list', () => {
assert.deepEqual(Statistics.findRangesForChangeDetectionsWithWelchsTTest([], [], 0.975), []);
});
it('should return an empty array if segmentation is empty list', () => {
assert.deepEqual(Statistics.findRangesForChangeDetectionsWithWelchsTTest([1,2,3], [], 0.975), []);
});
it('should return the range if computeWelchsT shows a significant change', () => {
const values = [
747.30337423744,
731.47392585276,
743.66763513161,
738.02055323487,
738.25426340842,
742.38680046471,
733.13921703284,
739.22069966147,
735.69295749633,
743.01705472504,
745.45778145306,
731.04841157169,
729.4372674973,
735.4497416527,
739.0230668644,
730.91782989909,
722.18725411279,
731.96223451728,
730.04119216192,
730.78087646284,
729.63155210365,
730.17585200878,
733.93766054706,
740.74920717197,
752.14718023647,
764.49990164847,
766.36100828473,
756.2291883252,
750.14522451097,
749.57595092266,
748.03624881866,
769.41522176386,
744.04660430456,
751.17927808265,
753.29996854062,
757.01813756936,
746.62413820741,
742.64420062736,
758.12726352772,
778.2278439089,
775.11818554541,
775.11818554541];
const segmentation = [{
seriesIndex: 0,
time: 1505176030671,
value: 736.5366704896555,
x: 370.4571789404566,
y: 185.52613334520248,
},
{
seriesIndex: 18,
time: 1515074391534,
value: 736.5366704896555,
x: 919.4183852714947,
y: 185.52613334520248
},
{
seriesIndex: 18,
time: 1515074391534,
value: 750.3483428383142,
x: 919.4183852714947,
y: 177.9710953409673,
},
{
seriesIndex: 41,
time: 1553851695869,
value: 750.3483428383142,
x: 3070.000290764446,
y: 177.9710953409673,
}];
assert.deepEqual(Statistics.findRangesForChangeDetectionsWithWelchsTTest(values, segmentation, 0.975), [
{
"endIndex": 29,
"segmentationEndValue": 750.3483428383142,
"segmentationStartValue": 736.5366704896555,
"startIndex": 6
}
]);
})
});
});