// Helpers const sum = (array) => array.reduce((a, b) => a + b, 0); const probabilityToOdds = (p) => p / (1 - p); const oddsToProbability = (o) => o / (1 + o); // Main functions export const median = (array) => { // needs validation array not empty let midway = Math.floor(array.length); 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) => { let result = sum(array) / array.length; return result; }; export const geometricMean = (array) => { // 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) => { 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 ) => { 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) => { 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; };