blob: 5ed631a17280ed3628907faeccdf9c29a95a501c [file] [log] [blame]
var Statistics = new (function () {
this.min = function (values) {
return Math.min.apply(Math, values);
}
this.max = function (values) {
return Math.max.apply(Math, values);
}
this.sum = function (values) {
return values.length ? values.reduce(function (a, b) { return a + b; }) : 0;
}
this.mean = function (values) {
return this.sum(values) / values.length;
}
this.weightedMean = function (valuesWithWeights) {
let totalWeight = 0;
let sum = 0;
for (const entry of valuesWithWeights) {
totalWeight += entry.weight;
sum += entry.value * entry.weight;
}
return sum / totalWeight;
}
this.median = function (values) {
return values.sort(function (a, b) { return a - b; })[Math.floor(values.length / 2)];
}
this.squareSum = function (values) {
return values.length ? values.reduce(function (sum, value) { return sum + value * value;}, 0) : 0;
}
// With sum and sum of squares, we can compute the sample standard deviation in O(1).
// See https://rniwa.com/2012-11-10/sample-standard-deviation-in-terms-of-sum-and-square-sum-of-samples/
this.sampleStandardDeviation = function (numberOfSamples, sum, squareSum) {
if (numberOfSamples < 2)
return 0;
return Math.sqrt(squareSum / (numberOfSamples - 1) - sum * sum / (numberOfSamples - 1) / numberOfSamples);
}
this.supportedConfidenceIntervalProbabilities = function () {
const supportedProbabilities = [];
for (const probability in tDistributionByOneSidedProbability)
supportedProbabilities.push(oneSidedToTwoSidedProbability(probability).toFixed(2));
return supportedProbabilities;
}
this.supportedOneSideTTestProbabilities = function () {
return Object.keys(tDistributionByOneSidedProbability);
}
// Computes the delta d s.t. (mean - d, mean + d) is the confidence interval with the specified probability in O(1).
this.confidenceIntervalDelta = function (probability, numberOfSamples, sum, squareSum) {
var oneSidedProbability = twoSidedToOneSidedProbability(probability);
if (!(oneSidedProbability in tDistributionByOneSidedProbability)) {
throw 'We only support ' + this.supportedConfidenceIntervalProbabilities().map(function (probability)
{ return probability * 100 + '%'; } ).join(', ') + ' confidence intervals.';
}
if (numberOfSamples - 2 < 0)
return NaN;
// d = c * S/sqrt(numberOfSamples) where c ~ t-distribution(degreesOfFreedom) and S is the sample standard deviation.
return this.minimumTForOneSidedProbability(oneSidedProbability, numberOfSamples - 1) * this.sampleStandardDeviation(numberOfSamples, sum, squareSum) / Math.sqrt(numberOfSamples);
}
this.confidenceInterval = function (values, probability) {
var sum = this.sum(values);
var mean = sum / values.length;
var delta = this.confidenceIntervalDelta(probability || 0.95, values.length, sum, this.squareSum(values));
return [mean - delta, mean + delta];
}
// Welch's t-test (http://en.wikipedia.org/wiki/Welch%27s_t_test)
this.testWelchsT = function (values1, values2, probability) {
return this.computeWelchsT(values1, 0, values1.length, values2, 0, values2.length, probability).significantlyDifferent;
}
function sampleMeanAndVarianceFromMultipleSamples(samples) {
let sum = 0;
let squareSum = 0;
let size = 0;
for (const sample of samples) {
sum += sample.sum;
squareSum += sample.squareSum;
size += sample.sampleSize;
}
const mean = sum / size;
const unbiasedSampleVariance = (squareSum - sum * sum / size) / (size - 1);
return {
mean,
variance: unbiasedSampleVariance,
size,
degreesOfFreedom: size - 1,
}
}
this.probabilityRangeForWelchsT = function (values1, values2) {
var result = this.computeWelchsT(values1, 0, values1.length, values2, 0, values2.length);
return this._determinetwoSidedProbabilityBoundaryForWelchsT(result.t, result.degreesOfFreedom);
}
this.probabilityRangeForWelchsTForMultipleSamples = function (sampleSet1, sampleSet2) {
const stat1 = sampleMeanAndVarianceFromMultipleSamples(sampleSet1);
const stat2 = sampleMeanAndVarianceFromMultipleSamples(sampleSet2);
const combinedT = this._computeWelchsTFromStatistics(stat1, stat2);
return this._determinetwoSidedProbabilityBoundaryForWelchsT(combinedT.t, combinedT.degreesOfFreedom)
}
this._determinetwoSidedProbabilityBoundaryForWelchsT = function(t, degreesOfFreedom) {
if (isNaN(t) || isNaN(degreesOfFreedom))
return {t: NaN, degreesOfFreedom:NaN, range: [null, null]};
let lowerBound = null;
let upperBound = null;
for (const probability in tDistributionByOneSidedProbability) {
const twoSidedProbability = oneSidedToTwoSidedProbability(probability);
if (t > this.minimumTForOneSidedProbability(probability, Math.round(degreesOfFreedom)))
lowerBound = twoSidedProbability;
else if (lowerBound) {
upperBound = twoSidedProbability;
break;
}
}
return {t, degreesOfFreedom, range: [lowerBound, upperBound]};
};
this.computeWelchsT = function (values1, startIndex1, length1, values2, startIndex2, length2, probability) {
const stat1 = sampleMeanAndVarianceForValues(values1, startIndex1, length1);
const stat2 = sampleMeanAndVarianceForValues(values2, startIndex2, length2);
const {t, degreesOfFreedom} = this._computeWelchsTFromStatistics(stat1, stat2);
const minT = this.minimumTForOneSidedProbability(twoSidedToOneSidedProbability(probability || 0.8), Math.round(degreesOfFreedom));
return {t, degreesOfFreedom, significantlyDifferent: t > minT};
};
this._computeWelchsTFromStatistics = function(stat1, stat2) {
const sumOfSampleVarianceOverSampleSize = stat1.variance / stat1.size + stat2.variance / stat2.size;
const t = Math.abs((stat1.mean - stat2.mean) / Math.sqrt(sumOfSampleVarianceOverSampleSize));
// http://en.wikipedia.org/wiki/Welch–Satterthwaite_equation
const degreesOfFreedom = sumOfSampleVarianceOverSampleSize * sumOfSampleVarianceOverSampleSize
/ (stat1.variance * stat1.variance / stat1.size / stat1.size / stat1.degreesOfFreedom
+ stat2.variance * stat2.variance / stat2.size / stat2.size / stat2.degreesOfFreedom);
return {t, degreesOfFreedom};
}
this.findRangesForChangeDetectionsWithWelchsTTest = function (values, segmentations, oneSidedPossibility=0.99) {
if (!values.length)
return [];
const selectedRanges = [];
const twoSidedFromOneSidedPossibility = 2 * oneSidedPossibility - 1;
for (let i = 1; i + 2 < segmentations.length; i += 2) {
let found = false;
const previousMean = segmentations[i].value;
const currentMean = segmentations[i + 1].value;
console.assert(currentMean != previousMean);
const currentChangePoint = segmentations[i].seriesIndex;
const start = segmentations[i - 1].seriesIndex;
const end = segmentations[i + 2].seriesIndex;
for (let leftEdge = currentChangePoint - 2, rightEdge = currentChangePoint + 2; leftEdge >= start && rightEdge <= end; leftEdge--, rightEdge++) {
const result = this.computeWelchsT(values, leftEdge, currentChangePoint - leftEdge, values, currentChangePoint, rightEdge - currentChangePoint, twoSidedFromOneSidedPossibility);
if (result.significantlyDifferent) {
selectedRanges.push({
startIndex: leftEdge,
endIndex: rightEdge - 1,
segmentationStartValue: previousMean,
segmentationEndValue: currentMean
});
found = true;
break;
}
}
if (!found && Statistics.debuggingTestingRangeNomination)
console.log('Failed to find a testing range at', currentChangePoint, 'changing from', previousMean, 'to', currentMean);
}
return selectedRanges;
};
function sampleMeanAndVarianceForValues(values, startIndex, length) {
var sum = 0;
for (var i = 0; i < length; i++)
sum += values[startIndex + i];
var squareSum = 0;
for (var i = 0; i < length; i++)
squareSum += values[startIndex + i] * values[startIndex + i];
var sampleMean = sum / length;
// FIXME: Maybe we should be using the biased sample variance.
var unbiasedSampleVariance = (squareSum - sum * sum / length) / (length - 1);
return {
mean: sampleMean,
variance: unbiasedSampleVariance,
size: length,
degreesOfFreedom: length - 1,
}
}
this.movingAverage = function (values, backwardWindowSize, forwardWindowSize) {
var averages = new Array(values.length);
// We use naive O(n^2) algorithm for simplicy as well as to avoid accumulating round-off errors.
for (var i = 0; i < values.length; i++) {
var sum = 0;
var count = 0;
for (var j = i - backwardWindowSize; j <= i + forwardWindowSize; j++) {
if (j >= 0 && j < values.length) {
sum += values[j];
count++;
}
}
averages[i] = sum / count;
}
return averages;
}
this.cumulativeMovingAverage = function (values) {
var averages = new Array(values.length);
var sum = 0;
for (var i = 0; i < values.length; i++) {
sum += values[i];
averages[i] = sum / (i + 1);
}
return averages;
}
this.exponentialMovingAverage = function (values, smoothingFactor) {
var averages = new Array(values.length);
var movingAverage = values[0];
averages[0] = movingAverage;
for (var i = 1; i < values.length; i++) {
movingAverage = smoothingFactor * values[i] + (1 - smoothingFactor) * movingAverage;
averages[i] = movingAverage;
}
return averages;
}
// The return value is the starting indices of each segment.
this.segmentTimeSeriesGreedyWithStudentsTTest = function (values, minLength) {
if (values.length < 2)
return [0];
var segments = new Array;
recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, 0, values.length, minLength, segments);
segments.push(values.length);
return segments;
}
this.debuggingSegmentation = false;
this.segmentTimeSeriesByMaximizingSchwarzCriterion = function (values, segmentCountWeight, gridSize) {
// Split the time series into grids since splitIntoSegmentsUntilGoodEnough is O(n^2).
var gridLength = gridSize || 500;
var totalSegmentation = [0];
for (var gridCount = 0; gridCount < Math.ceil(values.length / gridLength); gridCount++) {
var gridValues = values.slice(gridCount * gridLength, (gridCount + 1) * gridLength);
var segmentation = splitIntoSegmentsUntilGoodEnough(gridValues, segmentCountWeight);
if (Statistics.debuggingSegmentation)
console.log('grid=' + gridCount, segmentation);
for (var i = 1; i < segmentation.length - 1; i++)
totalSegmentation.push(gridCount * gridLength + segmentation[i]);
}
if (Statistics.debuggingSegmentation)
console.log('Final Segmentation', totalSegmentation);
totalSegmentation.push(values.length);
return totalSegmentation;
}
function recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, startIndex, length, minLength, segments) {
var tMax = 0;
var argTMax = null;
for (var i = 1; i < length - 1; i++) {
var firstLength = i;
var secondLength = length - i;
if (firstLength < minLength || secondLength < minLength)
continue;
var result = Statistics.computeWelchsT(values, startIndex, firstLength, values, startIndex + i, secondLength, 0.9);
if (result.significantlyDifferent && result.t > tMax) {
tMax = result.t;
argTMax = i;
}
}
if (!tMax) {
segments.push(startIndex);
return;
}
recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, startIndex, argTMax, minLength, segments);
recursivelySplitIntoTwoSegmentsAtMaxTIfSignificantlyDifferent(values, startIndex + argTMax, length - argTMax, minLength, segments);
}
this.minimumTForOneSidedProbability = function(probability, degreesOfFreedom) {
if (degreesOfFreedom < 1 || isNaN(degreesOfFreedom))
return NaN;
const tDistributionTableForProbability = tDistributionByOneSidedProbability[probability];
if (degreesOfFreedom <= tDistributionTableForProbability.probabilityToTValue.length)
return tDistributionTableForProbability.probabilityToTValue[degreesOfFreedom - 1];
const tValuesSortedByProbability = tDistributionTableForProbability.tValuesSortedByProbability;
let low = 0;
let high = tValuesSortedByProbability.length;
while (low < high) {
const mid = low + Math.floor((high - low) / 2);
const entry = tValuesSortedByProbability[mid];
if (degreesOfFreedom <= entry.maxDF)
high = mid;
else
low = mid + 1;
}
return tValuesSortedByProbability[low].value;
}
const tDistributionByOneSidedProbability = {
0.9: {
probabilityToTValue: [
3.0777, 1.8856, 1.6377, 1.5332, 1.4759, 1.4398, 1.4149, 1.3968, 1.383, 1.3722,
1.3634, 1.3562, 1.3502, 1.345, 1.3406, 1.3368, 1.3334, 1.3304, 1.3277, 1.3253,
1.3232, 1.3212, 1.3195, 1.3178, 1.3163, 1.315, 1.3137, 1.3125, 1.3114, 1.3104,
1.3095, 1.3086, 1.3077, 1.307, 1.3062, 1.3055, 1.3049, 1.3042, 1.3036, 1.3031,
1.3025, 1.302, 1.3016, 1.3011, 1.3006, 1.3002, 1.2998, 1.2994, 1.2991, 1.2987,
1.2984, 1.298, 1.2977, 1.2974, 1.2971, 1.2969, 1.2966, 1.2963, 1.2961, 1.2958,
1.2956, 1.2954, 1.2951, 1.2949, 1.2947, 1.2945, 1.2943, 1.2941, 1.2939, 1.2938,
1.2936, 1.2934, 1.2933, 1.2931, 1.2929, 1.2928, 1.2926, 1.2925, 1.2924, 1.2922,
1.2921, 1.292, 1.2918, 1.2917, 1.2916, 1.2915, 1.2914, 1.2912, 1.2911, 1.291,
1.2909, 1.2908, 1.2907, 1.2906, 1.2905, 1.2904, 1.2903, 1.2903, 1.2902, 1.2901
],
tValuesSortedByProbability: [
{maxDF: 101, value: 1.2900}, {maxDF: 102, value: 1.2899}, {maxDF: 103, value: 1.2898}, {maxDF: 105, value: 1.2897},
{maxDF: 106, value: 1.2896}, {maxDF: 107, value: 1.2895}, {maxDF: 109, value: 1.2894}, {maxDF: 110, value: 1.2893},
{maxDF: 112, value: 1.2892}, {maxDF: 113, value: 1.2891}, {maxDF: 115, value: 1.2890}, {maxDF: 116, value: 1.2889},
{maxDF: 118, value: 1.2888}, {maxDF: 119, value: 1.2887}, {maxDF: 121, value: 1.2886}, {maxDF: 123, value: 1.2885},
{maxDF: 125, value: 1.2884}, {maxDF: 127, value: 1.2883}, {maxDF: 128, value: 1.2882}, {maxDF: 130, value: 1.2881},
{maxDF: 132, value: 1.2880}, {maxDF: 135, value: 1.2879}, {maxDF: 137, value: 1.2878}, {maxDF: 139, value: 1.2877},
{maxDF: 141, value: 1.2876}, {maxDF: 144, value: 1.2875}, {maxDF: 146, value: 1.2874}, {maxDF: 149, value: 1.2873},
{maxDF: 151, value: 1.2872}, {maxDF: 154, value: 1.2871}, {maxDF: 157, value: 1.2870}, {maxDF: 160, value: 1.2869},
{maxDF: 163, value: 1.2868}, {maxDF: 166, value: 1.2867}, {maxDF: 170, value: 1.2866}, {maxDF: 173, value: 1.2865},
{maxDF: 177, value: 1.2864}, {maxDF: 180, value: 1.2863}, {maxDF: 184, value: 1.2862}, {maxDF: 188, value: 1.2861},
{maxDF: 193, value: 1.2860}, {maxDF: 197, value: 1.2859}, {maxDF: 202, value: 1.2858}, {maxDF: 207, value: 1.2857},
{maxDF: 212, value: 1.2856}, {maxDF: 217, value: 1.2855}, {maxDF: 223, value: 1.2854}, {maxDF: 229, value: 1.2853},
{maxDF: 235, value: 1.2852}, {maxDF: 242, value: 1.2851}, {maxDF: 249, value: 1.2850}, {maxDF: 257, value: 1.2849},
{maxDF: 265, value: 1.2848}, {maxDF: 273, value: 1.2847}, {maxDF: 283, value: 1.2846}, {maxDF: 292, value: 1.2845},
{maxDF: 303, value: 1.2844}, {maxDF: 314, value: 1.2843}, {maxDF: 326, value: 1.2842}, {maxDF: 339, value: 1.2841},
{maxDF: 353, value: 1.2840}, {maxDF: 369, value: 1.2839}, {maxDF: 385, value: 1.2838}, {maxDF: 404, value: 1.2837},
{maxDF: 424, value: 1.2836}, {maxDF: 446, value: 1.2835}, {maxDF: 471, value: 1.2834}, {maxDF: 499, value: 1.2833},
{maxDF: 530, value: 1.2832}, {maxDF: 565, value: 1.2831}, {maxDF: 606, value: 1.2830}, {maxDF: 652, value: 1.2829},
{maxDF: 707, value: 1.2828}, {maxDF: 771, value: 1.2827}, {maxDF: 848, value: 1.2826}, {maxDF: 942, value: 1.2825},
{maxDF: 1060, value: 1.2824}, {maxDF: 1212, value: 1.2823}, {maxDF: 1415, value: 1.2822}, {maxDF: 1699, value: 1.2821},
{maxDF: 2125, value: 1.2820}, {maxDF: 2837, value: 1.2819}, {maxDF: 4266, value: 1.2818}, {maxDF: 8601, value: 1.2817},
{maxDF: Infinity, value: 1.2816}
]
},
0.95: {
probabilityToTValue: [
6.3138, 2.92, 2.3534, 2.1318, 2.015, 1.9432, 1.8946, 1.8595, 1.8331, 1.8125,
1.7959, 1.7823, 1.7709, 1.7613, 1.7531, 1.7459, 1.7396, 1.7341, 1.7291, 1.7247,
1.7207, 1.7171, 1.7139, 1.7109, 1.7081, 1.7056, 1.7033, 1.7011, 1.6991, 1.6973,
1.6955, 1.6939, 1.6924, 1.6909, 1.6896, 1.6883, 1.6871, 1.686, 1.6849, 1.6839,
1.6829, 1.682, 1.6811, 1.6802, 1.6794, 1.6787, 1.6779, 1.6772, 1.6766, 1.6759,
1.6753, 1.6747, 1.6741, 1.6736, 1.673, 1.6725, 1.672, 1.6716, 1.6711, 1.6706,
1.6702, 1.6698, 1.6694, 1.669, 1.6686, 1.6683, 1.6679, 1.6676, 1.6672, 1.6669,
1.6666, 1.6663, 1.666, 1.6657, 1.6654, 1.6652, 1.6649, 1.6646, 1.6644, 1.6641,
1.6639, 1.6636, 1.6634, 1.6632, 1.663, 1.6628, 1.6626, 1.6624, 1.6622, 1.662,
1.6618, 1.6616, 1.6614, 1.6612, 1.6611, 1.6609, 1.6607, 1.6606, 1.6604, 1.6602,
1.6601, 1.6599, 1.6598, 1.6596, 1.6595, 1.6594, 1.6592, 1.6591, 1.659, 1.6588,
1.6587, 1.6586, 1.6585, 1.6583, 1.6582, 1.6581, 1.658, 1.6579, 1.6578, 1.6577
],
tValuesSortedByProbability: [
{maxDF: 121, value: 1.6575}, {maxDF: 122, value: 1.6574}, {maxDF: 123, value: 1.6573}, {maxDF: 124, value: 1.6572},
{maxDF: 125, value: 1.6571}, {maxDF: 126, value: 1.6570}, {maxDF: 127, value: 1.6569}, {maxDF: 129, value: 1.6568},
{maxDF: 130, value: 1.6567}, {maxDF: 131, value: 1.6566}, {maxDF: 132, value: 1.6565}, {maxDF: 133, value: 1.6564},
{maxDF: 134, value: 1.6563}, {maxDF: 135, value: 1.6562}, {maxDF: 137, value: 1.6561}, {maxDF: 138, value: 1.6560},
{maxDF: 139, value: 1.6559}, {maxDF: 140, value: 1.6558}, {maxDF: 142, value: 1.6557}, {maxDF: 143, value: 1.6556},
{maxDF: 144, value: 1.6555}, {maxDF: 146, value: 1.6554}, {maxDF: 147, value: 1.6553}, {maxDF: 148, value: 1.6552},
{maxDF: 150, value: 1.6551}, {maxDF: 151, value: 1.6550}, {maxDF: 153, value: 1.6549}, {maxDF: 154, value: 1.6548},
{maxDF: 156, value: 1.6547}, {maxDF: 158, value: 1.6546}, {maxDF: 159, value: 1.6545}, {maxDF: 161, value: 1.6544},
{maxDF: 163, value: 1.6543}, {maxDF: 164, value: 1.6542}, {maxDF: 166, value: 1.6541}, {maxDF: 168, value: 1.6540},
{maxDF: 170, value: 1.6539}, {maxDF: 172, value: 1.6538}, {maxDF: 174, value: 1.6537}, {maxDF: 176, value: 1.6536},
{maxDF: 178, value: 1.6535}, {maxDF: 180, value: 1.6534}, {maxDF: 182, value: 1.6533}, {maxDF: 184, value: 1.6532},
{maxDF: 186, value: 1.6531}, {maxDF: 189, value: 1.6530}, {maxDF: 191, value: 1.6529}, {maxDF: 193, value: 1.6528},
{maxDF: 196, value: 1.6527}, {maxDF: 198, value: 1.6526}, {maxDF: 201, value: 1.6525}, {maxDF: 204, value: 1.6524},
{maxDF: 206, value: 1.6523}, {maxDF: 209, value: 1.6522}, {maxDF: 212, value: 1.6521}, {maxDF: 215, value: 1.6520},
{maxDF: 218, value: 1.6519}, {maxDF: 221, value: 1.6518}, {maxDF: 225, value: 1.6517}, {maxDF: 228, value: 1.6516},
{maxDF: 231, value: 1.6515}, {maxDF: 235, value: 1.6514}, {maxDF: 239, value: 1.6513}, {maxDF: 242, value: 1.6512},
{maxDF: 246, value: 1.6511}, {maxDF: 250, value: 1.6510}, {maxDF: 255, value: 1.6509}, {maxDF: 259, value: 1.6508},
{maxDF: 263, value: 1.6507}, {maxDF: 268, value: 1.6506}, {maxDF: 273, value: 1.6505}, {maxDF: 278, value: 1.6504},
{maxDF: 283, value: 1.6503}, {maxDF: 288, value: 1.6502}, {maxDF: 294, value: 1.6501}, {maxDF: 299, value: 1.6500},
{maxDF: 305, value: 1.6499}, {maxDF: 312, value: 1.6498}, {maxDF: 318, value: 1.6497}, {maxDF: 325, value: 1.6496},
{maxDF: 332, value: 1.6495}, {maxDF: 339, value: 1.6494}, {maxDF: 347, value: 1.6493}, {maxDF: 355, value: 1.6492},
{maxDF: 364, value: 1.6491}, {maxDF: 372, value: 1.6490}, {maxDF: 382, value: 1.6489}, {maxDF: 392, value: 1.6488},
{maxDF: 402, value: 1.6487}, {maxDF: 413, value: 1.6486}, {maxDF: 424, value: 1.6485}, {maxDF: 436, value: 1.6484},
{maxDF: 449, value: 1.6483}, {maxDF: 463, value: 1.6482}, {maxDF: 477, value: 1.6481}, {maxDF: 493, value: 1.6480},
{maxDF: 509, value: 1.6479}, {maxDF: 527, value: 1.6478}, {maxDF: 545, value: 1.6477}, {maxDF: 566, value: 1.6476},
{maxDF: 587, value: 1.6475}, {maxDF: 611, value: 1.6474}, {maxDF: 636, value: 1.6473}, {maxDF: 664, value: 1.6472},
{maxDF: 694, value: 1.6471}, {maxDF: 727, value: 1.6470}, {maxDF: 764, value: 1.6469}, {maxDF: 804, value: 1.6468},
{maxDF: 849, value: 1.6467}, {maxDF: 899, value: 1.6466}, {maxDF: 955, value: 1.6465}, {maxDF: 1019, value: 1.6464},
{maxDF: 1092, value: 1.6463}, {maxDF: 1176, value: 1.6462}, {maxDF: 1274, value: 1.6461}, {maxDF: 1390, value: 1.6460},
{maxDF: 1530, value: 1.6459}, {maxDF: 1700, value: 1.6458}, {maxDF: 1914, value: 1.6457}, {maxDF: 2189, value: 1.6456},
{maxDF: 2555, value: 1.6455}, {maxDF: 3070, value: 1.6454}, {maxDF: 3845, value: 1.6453}, {maxDF: 5142, value: 1.6452},
{maxDF: 7760, value: 1.6451}, {maxDF: 15812, value: 1.6450}, {maxDF: Infinity, value: 1.6449}
]
},
0.975: {
probabilityToTValue: [
12.7062, 4.3027, 3.1824, 2.7764, 2.5706, 2.4469, 2.3646, 2.306, 2.2622, 2.2281,
2.201, 2.1788, 2.1604, 2.1448, 2.1314, 2.1199, 2.1098, 2.1009, 2.093, 2.086,
2.0796, 2.0739, 2.0687, 2.0639, 2.0595, 2.0555, 2.0518, 2.0484, 2.0452, 2.0423,
2.0395, 2.0369, 2.0345, 2.0322, 2.0301, 2.0281, 2.0262, 2.0244, 2.0227, 2.0211,
2.0195, 2.0181, 2.0167, 2.0154, 2.0141, 2.0129, 2.0117, 2.0106, 2.0096, 2.0086,
2.0076, 2.0066, 2.0057, 2.0049, 2.004, 2.0032, 2.0025, 2.0017, 2.001, 2.0003,
1.9996, 1.999, 1.9983, 1.9977, 1.9971, 1.9966, 1.996, 1.9955, 1.9949, 1.9944,
1.9939, 1.9935, 1.993, 1.9925, 1.9921, 1.9917, 1.9913, 1.9908, 1.9905, 1.9901,
1.9897, 1.9893, 1.989, 1.9886, 1.9883, 1.9879, 1.9876, 1.9873, 1.987, 1.9867,
1.9864, 1.9861, 1.9858, 1.9855, 1.9853, 1.985, 1.9847, 1.9845, 1.9842, 1.984,
1.9837, 1.9835, 1.9833, 1.983, 1.9828, 1.9826, 1.9824, 1.9822, 1.982, 1.9818,
1.9816, 1.9814, 1.9812, 1.981, 1.9808, 1.9806, 1.9804, 1.9803, 1.9801, 1.9799,
1.9798, 1.9796, 1.9794, 1.9793, 1.9791, 1.979, 1.9788, 1.9787, 1.9785, 1.9784,
1.9782, 1.9781, 1.978, 1.9778, 1.9777, 1.9776, 1.9774, 1.9773, 1.9772, 1.9771,
1.9769, 1.9768, 1.9767, 1.9766, 1.9765, 1.9763, 1.9762, 1.9761, 1.976, 1.9759,
1.9758, 1.9757, 1.9756, 1.9755, 1.9754, 1.9753, 1.9752, 1.9751, 1.975, 1.9749,
1.9748, 1.9747, 1.9746, 1.9745
],
tValuesSortedByProbability: [
{maxDF: 166, value: 1.9744}, {maxDF: 167, value: 1.9743}, {maxDF: 168, value: 1.9742}, {maxDF: 169, value: 1.9741},
{maxDF: 170, value: 1.9740}, {maxDF: 172, value: 1.9739}, {maxDF: 173, value: 1.9738}, {maxDF: 174, value: 1.9737},
{maxDF: 175, value: 1.9736}, {maxDF: 177, value: 1.9735}, {maxDF: 178, value: 1.9734}, {maxDF: 179, value: 1.9733},
{maxDF: 181, value: 1.9732}, {maxDF: 182, value: 1.9731}, {maxDF: 183, value: 1.9730}, {maxDF: 185, value: 1.9729},
{maxDF: 186, value: 1.9728}, {maxDF: 188, value: 1.9727}, {maxDF: 189, value: 1.9726}, {maxDF: 191, value: 1.9725},
{maxDF: 192, value: 1.9724}, {maxDF: 194, value: 1.9723}, {maxDF: 195, value: 1.9722}, {maxDF: 197, value: 1.9721},
{maxDF: 199, value: 1.9720}, {maxDF: 200, value: 1.9719}, {maxDF: 202, value: 1.9718}, {maxDF: 204, value: 1.9717},
{maxDF: 205, value: 1.9716}, {maxDF: 207, value: 1.9715}, {maxDF: 209, value: 1.9714}, {maxDF: 211, value: 1.9713},
{maxDF: 213, value: 1.9712}, {maxDF: 215, value: 1.9711}, {maxDF: 217, value: 1.9710}, {maxDF: 219, value: 1.9709},
{maxDF: 221, value: 1.9708}, {maxDF: 223, value: 1.9707}, {maxDF: 225, value: 1.9706}, {maxDF: 227, value: 1.9705},
{maxDF: 229, value: 1.9704}, {maxDF: 231, value: 1.9703}, {maxDF: 234, value: 1.9702}, {maxDF: 236, value: 1.9701},
{maxDF: 238, value: 1.9700}, {maxDF: 241, value: 1.9699}, {maxDF: 243, value: 1.9698}, {maxDF: 246, value: 1.9697},
{maxDF: 248, value: 1.9696}, {maxDF: 251, value: 1.9695}, {maxDF: 253, value: 1.9694}, {maxDF: 256, value: 1.9693},
{maxDF: 259, value: 1.9692}, {maxDF: 262, value: 1.9691}, {maxDF: 265, value: 1.9690}, {maxDF: 268, value: 1.9689},
{maxDF: 271, value: 1.9688}, {maxDF: 274, value: 1.9687}, {maxDF: 277, value: 1.9686}, {maxDF: 280, value: 1.9685},
{maxDF: 284, value: 1.9684}, {maxDF: 287, value: 1.9683}, {maxDF: 290, value: 1.9682}, {maxDF: 294, value: 1.9681},
{maxDF: 298, value: 1.9680}, {maxDF: 302, value: 1.9679}, {maxDF: 305, value: 1.9678}, {maxDF: 309, value: 1.9677},
{maxDF: 313, value: 1.9676}, {maxDF: 318, value: 1.9675}, {maxDF: 322, value: 1.9674}, {maxDF: 326, value: 1.9673},
{maxDF: 331, value: 1.9672}, {maxDF: 335, value: 1.9671}, {maxDF: 340, value: 1.9670}, {maxDF: 345, value: 1.9669},
{maxDF: 350, value: 1.9668}, {maxDF: 355, value: 1.9667}, {maxDF: 361, value: 1.9666}, {maxDF: 366, value: 1.9665},
{maxDF: 372, value: 1.9664}, {maxDF: 378, value: 1.9663}, {maxDF: 384, value: 1.9662}, {maxDF: 390, value: 1.9661},
{maxDF: 397, value: 1.9660}, {maxDF: 404, value: 1.9659}, {maxDF: 411, value: 1.9658}, {maxDF: 418, value: 1.9657},
{maxDF: 425, value: 1.9656}, {maxDF: 433, value: 1.9655}, {maxDF: 441, value: 1.9654}, {maxDF: 449, value: 1.9653},
{maxDF: 458, value: 1.9652}, {maxDF: 467, value: 1.9651}, {maxDF: 476, value: 1.9650}, {maxDF: 486, value: 1.9649},
{maxDF: 496, value: 1.9648}, {maxDF: 507, value: 1.9647}, {maxDF: 518, value: 1.9646}, {maxDF: 530, value: 1.9645},
{maxDF: 542, value: 1.9644}, {maxDF: 554, value: 1.9643}, {maxDF: 567, value: 1.9642}, {maxDF: 581, value: 1.9641},
{maxDF: 596, value: 1.9640}, {maxDF: 611, value: 1.9639}, {maxDF: 627, value: 1.9638}, {maxDF: 644, value: 1.9637},
{maxDF: 662, value: 1.9636}, {maxDF: 681, value: 1.9635}, {maxDF: 701, value: 1.9634}, {maxDF: 723, value: 1.9633},
{maxDF: 745, value: 1.9632}, {maxDF: 769, value: 1.9631}, {maxDF: 795, value: 1.9630}, {maxDF: 823, value: 1.9629},
{maxDF: 852, value: 1.9628}, {maxDF: 884, value: 1.9627}, {maxDF: 918, value: 1.9626}, {maxDF: 955, value: 1.9625},
{maxDF: 995, value: 1.9624}, {maxDF: 1038, value: 1.9623}, {maxDF: 1086, value: 1.9622}, {maxDF: 1138, value: 1.9621},
{maxDF: 1195, value: 1.9620}, {maxDF: 1259, value: 1.9619}, {maxDF: 1329, value: 1.9618}, {maxDF: 1408, value: 1.9617},
{maxDF: 1496, value: 1.9616}, {maxDF: 1597, value: 1.9615}, {maxDF: 1712, value: 1.9614}, {maxDF: 1845, value: 1.9613},
{maxDF: 2001, value: 1.9612}, {maxDF: 2185, value: 1.9611}, {maxDF: 2407, value: 1.9610}, {maxDF: 2678, value: 1.9609},
{maxDF: 3019, value: 1.9608}, {maxDF: 3459, value: 1.9607}, {maxDF: 4049, value: 1.9606}, {maxDF: 4882, value: 1.9605},
{maxDF: 6146, value: 1.9604}, {maxDF: 8295, value: 1.9603}, {maxDF: 12754, value: 1.9602}, {maxDF: 27580, value: 1.9601},
{maxDF: Infinity, value: 1.9600}
]
},
0.99: {
probabilityToTValue: [
31.8205, 6.9646, 4.5407, 3.7469, 3.3649, 3.1427, 2.998, 2.8965, 2.8214, 2.7638,
2.7181, 2.681, 2.6503, 2.6245, 2.6025, 2.5835, 2.5669, 2.5524, 2.5395, 2.528,
2.5176, 2.5083, 2.4999, 2.4922, 2.4851, 2.4786, 2.4727, 2.4671, 2.462, 2.4573,
2.4528, 2.4487, 2.4448, 2.4411, 2.4377, 2.4345, 2.4314, 2.4286, 2.4258, 2.4233,
2.4208, 2.4185, 2.4163, 2.4141, 2.4121, 2.4102, 2.4083, 2.4066, 2.4049, 2.4033,
2.4017, 2.4002, 2.3988, 2.3974, 2.3961, 2.3948, 2.3936, 2.3924, 2.3912, 2.3901,
2.389, 2.388, 2.387, 2.386, 2.3851, 2.3842, 2.3833, 2.3824, 2.3816, 2.3808,
2.38, 2.3793, 2.3785, 2.3778, 2.3771, 2.3764, 2.3758, 2.3751, 2.3745, 2.3739,
2.3733, 2.3727, 2.3721, 2.3716, 2.371, 2.3705, 2.37, 2.3695, 2.369, 2.3685,
2.368, 2.3676, 2.3671, 2.3667, 2.3662, 2.3658, 2.3654, 2.365, 2.3646, 2.3642,
2.3638, 2.3635, 2.3631, 2.3627, 2.3624, 2.362, 2.3617, 2.3614, 2.361, 2.3607,
2.3604, 2.3601, 2.3598, 2.3595, 2.3592, 2.3589, 2.3586, 2.3584, 2.3581, 2.3578,
2.3576, 2.3573, 2.357, 2.3568, 2.3565, 2.3563, 2.3561, 2.3558, 2.3556, 2.3554,
2.3552, 2.3549, 2.3547, 2.3545, 2.3543, 2.3541, 2.3539, 2.3537, 2.3535, 2.3533,
2.3531, 2.3529, 2.3527, 2.3525, 2.3523, 2.3522, 2.352, 2.3518, 2.3516, 2.3515,
2.3513, 2.3511, 2.351, 2.3508, 2.3506, 2.3505, 2.3503, 2.3502, 2.35, 2.3499,
2.3497, 2.3496, 2.3494, 2.3493, 2.3492, 2.349, 2.3489, 2.3487, 2.3486, 2.3485,
2.3484, 2.3482, 2.3481, 2.348, 2.3478, 2.3477, 2.3476, 2.3475, 2.3474, 2.3472,
2.3471, 2.347, 2.3469, 2.3468, 2.3467, 2.3466, 2.3465, 2.3463, 2.3462, 2.3461,
2.346, 2.3459, 2.3458, 2.3457, 2.3456, 2.3455, 2.3454, 2.3453, 2.3452, 2.3451
],
tValuesSortedByProbability: [
{maxDF: 201, value: 2.3450}, {maxDF: 203, value: 2.3449}, {maxDF: 204, value: 2.3448}, {maxDF: 205, value: 2.3447},
{maxDF: 206, value: 2.3446}, {maxDF: 207, value: 2.3445}, {maxDF: 208, value: 2.3444}, {maxDF: 209, value: 2.3443},
{maxDF: 211, value: 2.3442}, {maxDF: 212, value: 2.3441}, {maxDF: 213, value: 2.3440}, {maxDF: 214, value: 2.3439},
{maxDF: 215, value: 2.3438}, {maxDF: 217, value: 2.3437}, {maxDF: 218, value: 2.3436}, {maxDF: 219, value: 2.3435},
{maxDF: 220, value: 2.3434}, {maxDF: 222, value: 2.3433}, {maxDF: 223, value: 2.3432}, {maxDF: 224, value: 2.3431},
{maxDF: 226, value: 2.3430}, {maxDF: 227, value: 2.3429}, {maxDF: 228, value: 2.3428}, {maxDF: 230, value: 2.3427},
{maxDF: 231, value: 2.3426}, {maxDF: 233, value: 2.3425}, {maxDF: 234, value: 2.3424}, {maxDF: 236, value: 2.3423},
{maxDF: 237, value: 2.3422}, {maxDF: 239, value: 2.3421}, {maxDF: 240, value: 2.3420}, {maxDF: 242, value: 2.3419},
{maxDF: 243, value: 2.3418}, {maxDF: 245, value: 2.3417}, {maxDF: 246, value: 2.3416}, {maxDF: 248, value: 2.3415},
{maxDF: 250, value: 2.3414}, {maxDF: 251, value: 2.3413}, {maxDF: 253, value: 2.3412}, {maxDF: 255, value: 2.3411},
{maxDF: 256, value: 2.3410}, {maxDF: 258, value: 2.3409}, {maxDF: 260, value: 2.3408}, {maxDF: 262, value: 2.3407},
{maxDF: 264, value: 2.3406}, {maxDF: 265, value: 2.3405}, {maxDF: 267, value: 2.3404}, {maxDF: 269, value: 2.3403},
{maxDF: 271, value: 2.3402}, {maxDF: 273, value: 2.3401}, {maxDF: 275, value: 2.3400}, {maxDF: 277, value: 2.3399},
{maxDF: 279, value: 2.3398}, {maxDF: 281, value: 2.3397}, {maxDF: 283, value: 2.3396}, {maxDF: 286, value: 2.3395},
{maxDF: 288, value: 2.3394}, {maxDF: 290, value: 2.3393}, {maxDF: 292, value: 2.3392}, {maxDF: 295, value: 2.3391},
{maxDF: 297, value: 2.3390}, {maxDF: 299, value: 2.3389}, {maxDF: 302, value: 2.3388}, {maxDF: 304, value: 2.3387},
{maxDF: 307, value: 2.3386}, {maxDF: 309, value: 2.3385}, {maxDF: 312, value: 2.3384}, {maxDF: 314, value: 2.3383},
{maxDF: 317, value: 2.3382}, {maxDF: 320, value: 2.3381}, {maxDF: 322, value: 2.3380}, {maxDF: 325, value: 2.3379},
{maxDF: 328, value: 2.3378}, {maxDF: 331, value: 2.3377}, {maxDF: 334, value: 2.3376}, {maxDF: 337, value: 2.3375},
{maxDF: 340, value: 2.3374}, {maxDF: 343, value: 2.3373}, {maxDF: 346, value: 2.3372}, {maxDF: 349, value: 2.3371},
{maxDF: 353, value: 2.3370}, {maxDF: 356, value: 2.3369}, {maxDF: 360, value: 2.3368}, {maxDF: 363, value: 2.3367},
{maxDF: 367, value: 2.3366}, {maxDF: 370, value: 2.3365}, {maxDF: 374, value: 2.3364}, {maxDF: 378, value: 2.3363},
{maxDF: 381, value: 2.3362}, {maxDF: 385, value: 2.3361}, {maxDF: 389, value: 2.3360}, {maxDF: 393, value: 2.3359},
{maxDF: 398, value: 2.3358}, {maxDF: 402, value: 2.3357}, {maxDF: 406, value: 2.3356}, {maxDF: 411, value: 2.3355},
{maxDF: 415, value: 2.3354}, {maxDF: 420, value: 2.3353}, {maxDF: 425, value: 2.3352}, {maxDF: 430, value: 2.3351},
{maxDF: 435, value: 2.3350}, {maxDF: 440, value: 2.3349}, {maxDF: 445, value: 2.3348}, {maxDF: 450, value: 2.3347},
{maxDF: 456, value: 2.3346}, {maxDF: 461, value: 2.3345}, {maxDF: 467, value: 2.3344}, {maxDF: 473, value: 2.3343},
{maxDF: 479, value: 2.3342}, {maxDF: 485, value: 2.3341}, {maxDF: 492, value: 2.3340}, {maxDF: 498, value: 2.3339},
{maxDF: 505, value: 2.3338}, {maxDF: 512, value: 2.3337}, {maxDF: 519, value: 2.3336}, {maxDF: 526, value: 2.3335},
{maxDF: 534, value: 2.3334}, {maxDF: 541, value: 2.3333}, {maxDF: 549, value: 2.3332}, {maxDF: 557, value: 2.3331},
{maxDF: 566, value: 2.3330}, {maxDF: 575, value: 2.3329}, {maxDF: 584, value: 2.3328}, {maxDF: 593, value: 2.3327},
{maxDF: 602, value: 2.3326}, {maxDF: 612, value: 2.3325}, {maxDF: 622, value: 2.3324}, {maxDF: 633, value: 2.3323},
{maxDF: 644, value: 2.3322}, {maxDF: 655, value: 2.3321}, {maxDF: 667, value: 2.3320}, {maxDF: 679, value: 2.3319},
{maxDF: 691, value: 2.3318}, {maxDF: 704, value: 2.3317}, {maxDF: 718, value: 2.3316}, {maxDF: 732, value: 2.3315},
{maxDF: 747, value: 2.3314}, {maxDF: 762, value: 2.3313}, {maxDF: 778, value: 2.3312}, {maxDF: 794, value: 2.3311},
{maxDF: 811, value: 2.3310}, {maxDF: 829, value: 2.3309}, {maxDF: 848, value: 2.3308}, {maxDF: 868, value: 2.3307},
{maxDF: 888, value: 2.3306}, {maxDF: 910, value: 2.3305}, {maxDF: 933, value: 2.3304}, {maxDF: 957, value: 2.3303},
{maxDF: 982, value: 2.3302}, {maxDF: 1008, value: 2.3301}, {maxDF: 1036, value: 2.3300}, {maxDF: 1066, value: 2.3299},
{maxDF: 1097, value: 2.3298}, {maxDF: 1130, value: 2.3297}, {maxDF: 1166, value: 2.3296}, {maxDF: 1203, value: 2.3295},
{maxDF: 1243, value: 2.3294}, {maxDF: 1286, value: 2.3293}, {maxDF: 1332, value: 2.3292}, {maxDF: 1381, value: 2.3291},
{maxDF: 1434, value: 2.3290}, {maxDF: 1491, value: 2.3289}, {maxDF: 1553, value: 2.3288}, {maxDF: 1621, value: 2.3287},
{maxDF: 1694, value: 2.3286}, {maxDF: 1775, value: 2.3285}, {maxDF: 1864, value: 2.3284}, {maxDF: 1962, value: 2.3283},
{maxDF: 2070, value: 2.3282}, {maxDF: 2192, value: 2.3281}, {maxDF: 2329, value: 2.3280}, {maxDF: 2484, value: 2.3279},
{maxDF: 2661, value: 2.3278}, {maxDF: 2865, value: 2.3277}, {maxDF: 3103, value: 2.3276}, {maxDF: 3385, value: 2.3275},
{maxDF: 3722, value: 2.3274}, {maxDF: 4135, value: 2.3273}, {maxDF: 4650, value: 2.3272}, {maxDF: 5312, value: 2.3271},
{maxDF: 6194, value: 2.3270}, {maxDF: 7428, value: 2.3269}, {maxDF: 9274, value: 2.3268}, {maxDF: 12344, value: 2.3267},
{maxDF: 18450, value: 2.3266}, {maxDF: 36515, value: 2.3265}, {maxDF: 1754068, value: 2.3264}, {maxDF: Infinity, value: 2.3263}
]
},
};
function oneSidedToTwoSidedProbability(probability) { return 2 * probability - 1; }
function twoSidedToOneSidedProbability(probability) { return (1 - (1 - probability) / 2); }
function splitIntoSegmentsUntilGoodEnough(values, BirgeAndMassartC) {
if (values.length < 2)
return [0, values.length];
var matrix = new SampleVarianceUpperTriangularMatrix(values);
var SchwarzCriterionBeta = Math.log1p(values.length - 1) / values.length;
BirgeAndMassartC = BirgeAndMassartC || 2.5; // Suggested by the authors.
var BirgeAndMassartPenalization = function (segmentCount) {
return segmentCount * (1 + BirgeAndMassartC * Math.log1p(values.length / segmentCount - 1));
}
var segmentation;
var minTotalCost = Infinity;
var maxK = Math.min(50, values.length);
for (var k = 1; k < maxK; k++) {
var start = Date.now();
var result = findOptimalSegmentation(values, matrix, k);
var cost = result.cost / values.length;
var penalty = SchwarzCriterionBeta * BirgeAndMassartPenalization(k);
if (cost + penalty < minTotalCost) {
minTotalCost = cost + penalty;
segmentation = result.segmentation;
} else
maxK = Math.min(maxK, k + 3);
if (Statistics.debuggingSegmentation)
console.log('splitIntoSegmentsUntilGoodEnough', k, Date.now() - start, cost + penalty);
}
return segmentation;
}
function allocateCostUpperTriangularForSegmentation(values, segmentCount)
{
// Dynamic programming. cost[i][k] = The cost to segmenting values up to i into k segments.
var cost = new Array(values.length);
for (var segmentEnd = 0; segmentEnd < values.length; segmentEnd++)
cost[segmentEnd] = new Float32Array(segmentCount + 1);
return cost;
}
function allocatePreviousNodeForSegmentation(values, segmentCount)
{
// previousNode[i][k] = The start of the last segment in an optimal segmentation that ends at i with k segments.
var previousNode = new Array(values.length);
for (var i = 0; i < values.length; i++)
previousNode[i] = new Array(segmentCount + 1);
return previousNode;
}
function findOptimalSegmentationInternal(cost, previousNode, values, costMatrix, segmentCount)
{
cost[0] = [0]; // The cost of segmenting single value is always 0.
previousNode[0] = [-1];
for (var segmentStart = 0; segmentStart < values.length; segmentStart++) {
var costOfOptimalSegmentationThatEndAtCurrentStart = cost[segmentStart];
for (var k = 0; k < segmentCount; k++) {
var noSegmentationOfLenghtKEndsAtCurrentStart = previousNode[segmentStart][k] === undefined;
if (noSegmentationOfLenghtKEndsAtCurrentStart)
continue;
for (var segmentEnd = segmentStart + 1; segmentEnd < values.length; segmentEnd++) {
var costOfOptimalSegmentationOfLengthK = costOfOptimalSegmentationThatEndAtCurrentStart[k];
var costOfCurrentSegment = costMatrix.costBetween(segmentStart, segmentEnd);
var totalCost = costOfOptimalSegmentationOfLengthK + costOfCurrentSegment;
if (previousNode[segmentEnd][k + 1] === undefined || totalCost < cost[segmentEnd][k + 1]) {
cost[segmentEnd][k + 1] = totalCost;
previousNode[segmentEnd][k + 1] = segmentStart;
}
}
}
}
}
function findOptimalSegmentation(values, costMatrix, segmentCount) {
var cost = allocateCostUpperTriangularForSegmentation(values, segmentCount);
var previousNode = allocatePreviousNodeForSegmentation(values, segmentCount);
findOptimalSegmentationInternal(cost, previousNode, values, costMatrix, segmentCount);
if (Statistics.debuggingSegmentation) {
console.log('findOptimalSegmentation with', segmentCount, 'segments');
for (var end = 0; end < values.length; end++) {
for (var k = 0; k <= segmentCount; k++) {
var start = previousNode[end][k];
if (start === undefined)
continue;
console.log(`C(segment=[${start}, ${end + 1}], segmentCount=${k})=${cost[end][k]}`);
}
}
}
var segmentEnd = values.length - 1;
var segmentation = new Array(segmentCount + 1);
segmentation[segmentCount] = values.length;
for (var k = segmentCount; k > 0; k--) {
segmentEnd = previousNode[segmentEnd][k];
segmentation[k - 1] = segmentEnd;
}
var costOfOptimalSegmentation = cost[values.length - 1][segmentCount];
if (Statistics.debuggingSegmentation)
console.log('Optimal segmentation:', segmentation, 'with cost =', costOfOptimalSegmentation);
return {segmentation: segmentation, cost: costOfOptimalSegmentation};
}
function SampleVarianceUpperTriangularMatrix(values) {
// The cost of segment (i, j].
var costMatrix = new Array(values.length - 1);
for (var i = 0; i < values.length - 1; i++) {
var remainingValueCount = values.length - i - 1;
costMatrix[i] = new Float32Array(remainingValueCount);
var sum = values[i];
var squareSum = sum * sum;
costMatrix[i][0] = 0;
for (var j = i + 1; j < values.length; j++) {
var currentValue = values[j];
sum += currentValue;
squareSum += currentValue * currentValue;
var sampleSize = j - i + 1;
var stdev = Statistics.sampleStandardDeviation(sampleSize, sum, squareSum);
costMatrix[i][j - i - 1] = stdev > 0 ? sampleSize * Math.log(stdev * stdev) : 0;
}
}
this.costMatrix = costMatrix;
}
SampleVarianceUpperTriangularMatrix.prototype.costBetween = function(from, to) {
if (from >= this.costMatrix.length || from == to)
return 0; // The cost of the segment that starts at the last data point is 0.
return this.costMatrix[from][to - from - 1];
}
})();
if (typeof module != 'undefined')
module.exports = Statistics;