UNPKG

locutus

Version:

Locutus other languages' standard libraries to JavaScript for fun and educational purposes

73 lines (72 loc) 2.96 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.variance = variance; function variance(data, xbar) { // discuss at: https://locutus.io/python/statistics/variance/ // parity verified: Python 3.12 // original by: Kevin van Zonneveld (https://kvz.io) // note 1: Returns the sample variance and preserves exact integer results when Python does. // example 1: variance([1, 2, 3]) // returns 1: 1 // example 2: variance([1, 3]) // returns 2: 2 // example 3: variance([1, 2, 3], 2) // returns 3: 1 const sequence = toNumericSequence(data, 'variance'); if (sequence.values.length < 2) { throw new Error('variance requires at least two data points'); } return statisticsVarianceFromSequence(sequence, sequence.values.length - 1, 'variance', xbar); } function toNumericSequence(data, functionName) { const values = assertStatisticsArray(data, functionName); return { values: values.map((value) => toStatisticNumber(value, functionName)), integral: values.every(isIntegralStatisticValue), }; } function statisticsVarianceFromSequence(sequence, divisor, functionName, center) { const mean = center === undefined ? statisticsMeanFromSequence(sequence) : toStatisticNumber(center, functionName); const squaredDeltaSum = sequence.values.reduce((sum, value) => { const delta = value - mean; return sum + delta * delta; }, 0); return divideStatisticsValue(squaredDeltaSum, divisor, sequence.integral); } function statisticsMeanFromSequence(sequence) { return divideStatisticsValue(sumNumbers(sequence.values), sequence.values.length, sequence.integral); } function assertStatisticsArray(data, functionName) { if (!Array.isArray(data)) { throw new TypeError(`${functionName}() data must be an array`); } return data; } function toStatisticNumber(value, functionName) { if (typeof value === 'number') { return value; } if (typeof value === 'boolean') { return value ? 1 : 0; } if (typeof value === 'bigint') { const numericValue = Number(value); if (!Number.isSafeInteger(numericValue)) { throw new RangeError(`${functionName}() bigint values must fit within JS safe integers`); } return numericValue; } throw new TypeError(`${functionName}() data must contain only real numbers`); } function isIntegralStatisticValue(value) { return (typeof value === 'boolean' || typeof value === 'bigint' || (typeof value === 'number' && Number.isInteger(value))); } function sumNumbers(values) { return values.reduce((sum, value) => sum + value, 0); } function divideStatisticsValue(total, divisor, integral) { if (integral && Number.isSafeInteger(total) && total % divisor === 0) { return total / divisor; } return total / divisor; }