spee.ch/server/models/utils/trendingAnalysis.js
2018-11-12 14:31:34 -05:00

68 lines
1.6 KiB
JavaScript

const ZSCORE_CRITICAL_THRESHOLD = 1.96; // 95-percentile
const ZSCORE_NINETYNINTH = 2.326347875; // 99-percentile
const ONE_DIV_SQRT_2PI = 0.3989422804014327; // V8 float of 1/SQRT(2 * PI)
const MAX_P_PRECISION = Math.exp(-16); // Rought estimation of V8 precision, -16 is 1.1253517471925912e-7
const MIN_P = -6.44357455534; // v8 float 0.0...0
const MAX_P = 6.44357455534; // v8 float 1.0...0
const getMean = (numArr) => {
let total = 0;
let length = numArr.length; // store local to reduce potential prop lookups
for (let i = 0; i < length; i++) {
total += numArr[i];
}
return total / length;
};
const getStandardDeviation = (numArr, mean) => {
return Math.sqrt(numArr.reduce((sq, n) => (
sq + Math.pow(n - mean, 2)
), 0) / (numArr.length - 1));
};
const getInformationFromValues = (numArr) => {
let mean = getMean(numArr);
return {
mean,
standardDeviation: getStandardDeviation(numArr, mean),
};
};
const getZScore = (value, mean, sDeviation) => (sDeviation !== 0 ? (value - mean) / sDeviation : 0);
const getFastPValue = (zScore) => {
if (zScore <= MIN_P) {
return 0;
}
if (zScore >= MAX_P) {
return 1;
}
let factorialK = 1;
let k = 0;
let sum = 0;
let term = 1;
while (Math.abs(term) > MAX_P_PRECISION) {
term = ONE_DIV_SQRT_2PI * Math.pow(-1, k) * Math.pow(zScore, k) / (2 * k + 1) / Math.pow(2, k) * Math.pow(zScore, k + 1) / factorialK;
sum += term;
k++;
factorialK *= k;
}
sum += 0.5;
return sum;
};
const getWeight = (zScore, pValue) => (zScore * pValue);
module.exports = {
getInformationFromValues,
getZScore,
getFastPValue,
getWeight,
};