@basementuniverse/stats
Version:
Basic statistics functions
254 lines • 13.6 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.histogram = exports.outliers = exports.iqr = exports.standardDeviation = exports.variance = exports.range = exports.mode = exports.median = exports.mean = exports.maxArray = exports.minArray = void 0;
/**
* Safe version of `Math.min`
*
* Native `Math.min` throws:
* ```
* `Uncaught RangeError: Maximum call stack size exceeded`
* ```
* when passing in a huge number of arguments (>~100k).
* @param {number[]} a An array of numbers
* @returns {number} The minimum number from the array
*/
function minArray(a) {
let length = a.length;
let min = Infinity;
while (length--) {
min = a[length] < min ? a[length] : min;
}
return min;
}
exports.minArray = minArray;
/**
* Safe version of `Math.max`
*
* Native `Math.max` throws:
* ```
* `Uncaught RangeError: Maximum call stack size exceeded`
* ```
* when passing in a huge number of arguments (>~100k).
* @param {number[]} a An array of numbers
* @returns {number} The maximum number from the array
*/
function maxArray(a) {
let length = a.length;
let max = -Infinity;
while (length--) {
max = a[length] > max ? a[length] : max;
}
return max;
}
exports.maxArray = maxArray;
/**
* Find the mean of a list of numbers
* @param {number[]} data An array of numbers
* @returns {number} The mean of a list of numbers
*/
function mean(data) {
const { length: n } = data;
if (!n) {
return 0;
}
return data.reduce((a, c) => a + c, 0) / n;
}
exports.mean = mean;
/**
* Find the median of a list of numbers
* @param {number[]} data An array of numbers
* @returns {number} The median of a list of numbers
*/
function median(data) {
const { length: n } = data;
if (!n) {
return 0;
}
const sortedData = [...data].sort((a, b) => a - b);
if (n % 2 === 0) {
return mean([sortedData[n / 2 - 1], sortedData[n / 2]]);
}
return sortedData[(n - 1) / 2];
}
exports.median = median;
/**
* Find the mode of a list of numbers
* @param {number[]} data An array of numbers
* @returns {number} The mode of a list of numbers
*/
function mode(data) {
const { length: n } = data;
if (!n) {
return 0;
}
const mode = {};
let max = 0, count = 0;
data.forEach(v => {
var _a;
mode[v] = ((_a = mode[v]) !== null && _a !== void 0 ? _a : 0) + 1;
if (mode[v] > count) {
max = v;
count = mode[v];
}
});
return max;
}
exports.mode = mode;
/**
* Find the range of a list of numbers
* @param {number[]} data An array of numbers
* @returns {object} An object containing the min, max and range
* @example Returned format:
* ```
* {
* min: 1,
* max: 5,
* range: 4
* }
* ```
*/
function range(data) {
const { length: n } = data;
if (!n) {
return {
min: 0,
max: 0,
range: 0,
};
}
const min = minArray(data), max = maxArray(data);
return {
min,
max,
range: max - min,
};
}
exports.range = range;
/**
* Calculate the variance of a list of numbers
* @param {number[]} data An array of numbers
* @param {boolean} sample True if the dataset is a sample
* @returns {number} The variance of a list of numbers
*/
function variance(data, sample = false) {
const { length: n } = data;
if (!n) {
return 0;
}
if (sample && n === 1) {
return 0;
}
const mu = mean(data);
return data.map(n => Math.pow(n - mu, 2)).reduce((a, c) => a + c, 0) / (sample
? (n - 1)
: n);
}
exports.variance = variance;
/**
* Calculate the standard deviation of a list of numbers
* @param {number[]} data An array of numbers
* @param {boolean} sample True if the dataset is a sample
* @returns {number} The standard deviation of a list of numbers
*/
function standardDeviation(data, sample = false) {
return Math.sqrt(variance(data, sample));
}
exports.standardDeviation = standardDeviation;
/**
* Calculate the (exclusive) interquartile range of a list of numbers
* @param {number[]} data An array of numbers
* @returns {object} An object containing the Q1, Q2 and Q3 medians and interquartile range
* @example Returned format:
* ```
* {
* q1: 1,
* q2: 3,
* q3: 5,
* range: 4
* }
* ```
*/
function iqr(data) {
const { length: n } = data;
const half = n / 2;
if (n < 4) {
return { range: 0 };
}
const sortedData = [...data].sort((a, b) => a - b);
let q1 = 0, q3 = 0;
if (n % 2 === 0) {
q1 = median(sortedData.slice(0, half));
q3 = median(sortedData.slice(-half));
}
else {
q1 = median(sortedData.slice(0, Math.floor(half)));
q3 = median(sortedData.slice(-Math.floor(half)));
}
return {
q1,
q2: median(sortedData),
q3,
range: q3 - q1,
};
}
exports.iqr = iqr;
/**
* Find outliers in a list of numbers using the IQR method
* @param {number[]} data An array of numbers
* @returns {number[]} An array of indexes for the outliers
*/
function outliers(data) {
const { length: n } = data;
if (n < 4) {
return [];
}
const { q1, q3, range } = iqr(data);
if (q1 === undefined || q3 === undefined) {
return [];
}
const lower = q1 - 1.5 * range;
const upper = q3 + 1.5 * range;
return data
.map((v, i) => (v < lower || v > upper) ? i : -1)
.filter(v => v !== -1);
}
exports.outliers = outliers;
/**
* Generate a histogram by splitting data into buckets of the specified size
* and counting the frequency of items in each bucket
*
* Within each bucket, min is inclusive and max is exclusive
*
* @param {number[]} data An array of numbers
* @param {number} bucketWidth The width of each bucket
* @returns {Bucket[]} An array of buckets
* @example Returned format:
* ```
* [
* {
* min: 1,
* max: 3,
* frequency: 4
* }
* ]
* ```
*/
function histogram(data, bucketWidth = 1) {
const min = minArray(data);
const max = maxArray(data);
const buckets = [];
for (let i = min; i <= max; i += bucketWidth) {
buckets.push({
min: i,
max: i + bucketWidth,
frequency: 0,
});
}
data.forEach(v => {
const bucket = Math.floor((v - min) / bucketWidth);
buckets[bucket].frequency++;
});
return buckets;
}
exports.histogram = histogram;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQTs7Ozs7Ozs7OztHQVVHO0FBQ0gsU0FBZ0IsUUFBUSxDQUFDLENBQVc7SUFDbEMsSUFBSSxNQUFNLEdBQUcsQ0FBQyxDQUFDLE1BQU0sQ0FBQztJQUN0QixJQUFJLEdBQUcsR0FBRyxRQUFRLENBQUM7SUFFbkIsT0FBTyxNQUFNLEVBQUUsRUFBRTtRQUNmLEdBQUcsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztLQUN6QztJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQVJELDRCQVFDO0FBRUQ7Ozs7Ozs7Ozs7R0FVRztBQUNILFNBQWdCLFFBQVEsQ0FBQyxDQUFXO0lBQ2xDLElBQUksTUFBTSxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUM7SUFDdEIsSUFBSSxHQUFHLEdBQUcsQ0FBQyxRQUFRLENBQUM7SUFFcEIsT0FBTyxNQUFNLEVBQUUsRUFBRTtRQUNmLEdBQUcsR0FBRyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztLQUN6QztJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQVJELDRCQVFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQWdCLElBQUksQ0FBQyxJQUFjO0lBQ2pDLE1BQU0sRUFBRSxNQUFNLEVBQUUsQ0FBQyxFQUFFLEdBQUcsSUFBSSxDQUFDO0lBRTNCLElBQUksQ0FBQyxDQUFDLEVBQUU7UUFDTixPQUFPLENBQUMsQ0FBQztLQUNWO0lBRUQsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMs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
;