605 lines
36 KiB
JavaScript
605 lines
36 KiB
JavaScript
"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('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
|
||
}
|
||
]);
|
||
})
|
||
});
|
||
});
|