UNPKG

locutus

Version:

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

71 lines (70 loc) 2.69 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fmean = fmean; function fmean(data, weights) { // discuss at: https://locutus.io/python/statistics/fmean/ // parity verified: Python 3.12 // original by: Kevin van Zonneveld (https://kvz.io) // note 1: Returns the arithmetic mean as a float and supports optional numeric weights. // example 1: fmean([1, 2, 3]) // returns 1: 2 // example 2: fmean([1, 2, 3, 4]) // returns 2: 2.5 // example 3: fmean([3.5, 4, 5.25], [2, 3, 5]) // returns 3: 4.525 const sequence = toNumericSequence(data, 'fmean'); if (sequence.values.length === 0) { throw new Error('fmean requires at least one data point'); } if (weights === undefined) { return statisticsMeanFromSequence(sequence); } const weightValues = assertStatisticsArray(weights, 'fmean').map((value) => toStatisticNumber(value, 'fmean')); if (weightValues.length !== sequence.values.length) { throw new Error('fmean requires data and weights to be the same length'); } let totalWeight = 0; let weightedSum = 0; for (let index = 0; index < sequence.values.length; index += 1) { const weight = weightValues[index] ?? 0; totalWeight += weight; weightedSum += (sequence.values[index] ?? 0) * weight; } if (totalWeight <= 0) { throw new Error('fmean requires at least one positive weight'); } return weightedSum / totalWeight; } function toNumericSequence(data, functionName) { return { values: assertStatisticsArray(data, functionName).map((value) => toStatisticNumber(value, functionName)), }; } function statisticsMeanFromSequence(sequence) { return sumNumbers(sequence.values) / sequence.values.length; } 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 sumNumbers(values) { return values.reduce((sum, value) => sum + value, 0); }