forecasting/packages/aggregation/index.js
2022-04-24 18:50:03 -04:00

75 lines
2.4 KiB
JavaScript

// Helpers
const sum = (array) => array.reduce((a, b) => a + b, 0);
const probabilityToOdds = (p) => p / (1 - p);
const oddsToProbability = (o) => o / (1 + o);
const validateArray = (arr) =>
Array.isArray(arr) &&
arr.length > 0 &&
arr.reduce((a, b) => a && typeof b == "number" && b >= 0 && b <= 1, true);
// Main functions
export const median = (array) => {
if (!validateArray(array)) return -1;
// needs validation array not empty
let midway = Math.floor(array.length) / 2;
let arrayToBeSorted = [...array];
// sorting mutates the array, which I am averse to
let arraySorted = arrayToBeSorted.sort((a, b) => a - b);
if (midway % 2) {
return arraySorted[midway];
} else {
return (arraySorted[midway - 1] + arraySorted[midway]) / 2;
}
};
export const arithmeticMean = (array) => {
if (!validateArray(array)) return -1;
let result = sum(array) / array.length;
return result;
};
export const geometricMean = (array) => {
if (!validateArray(array)) return -1;
// sum of logs seems more numerically stable than multiplying a lot of numbers 0<=p<=1
let arrayAsLog = array.map((p) => Math.log(p));
let sumOfLogs = sum(arrayAsLog) / arrayAsLog.length;
let result = Math.exp(sumOfLogs);
return result;
};
export const geometricMeanOfOdds = (array) => {
if (!validateArray(array)) return -1;
let arrayOfOdds = array.map((p) => probabilityToOdds(p));
let arrayOfLogsOfOdds = arrayOfOdds.map((p) => Math.log(p));
let sumOfLogsOfOdds = sum(arrayOfLogsOfOdds) / arrayOfLogsOfOdds.length;
let geomMeanOfOdds = Math.exp(sumOfLogsOfOdds);
let result = oddsToProbability(geomMeanOfOdds);
return result;
};
export const extremizedGeometricMeanOfOdds = (
array,
extremizationParameter = 1.5
) => {
if (!validateArray(array)) return -1;
let arrayOfOdds = array.map((p) => probabilityToOdds(p));
let arrayOfLogsOfOdds = arrayOfOdds.map((p) => Math.log(p));
let extremizedSumOfLogsOfOdds =
(extremizationParameter * sum(arrayOfLogsOfOdds)) /
arrayOfLogsOfOdds.length;
let extremizedGeomMeanOfOdds = Math.exp(extremizedSumOfLogsOfOdds);
let result = oddsToProbability(extremizedGeomMeanOfOdds);
return result;
};
export const neyman = (array) => {
if (!validateArray(array)) return -1;
let n = array.length;
let d =
(n * (Math.sqrt(3 * Math.pow(n, 2) - 3 * n + 1) - 2)) /
(Math.pow(n, 2) - n - 1);
let result = extremizedGeometricMeanOfOdds(array, d);
return result;
};