variance.js (5726B)
1 import { deepForEach } from '../../utils/collection.js'; 2 import { isBigNumber } from '../../utils/is.js'; 3 import { factory } from '../../utils/factory.js'; 4 import { improveErrorMessage } from './utils/improveErrorMessage.js'; 5 var DEFAULT_NORMALIZATION = 'unbiased'; 6 var name = 'variance'; 7 var dependencies = ['typed', 'add', 'subtract', 'multiply', 'divide', 'apply', 'isNaN']; 8 export var createVariance = /* #__PURE__ */factory(name, dependencies, _ref => { 9 var { 10 typed, 11 add, 12 subtract, 13 multiply, 14 divide, 15 apply, 16 isNaN 17 } = _ref; 18 19 /** 20 * Compute the variance of a matrix or a list with values. 21 * In case of a (multi dimensional) array or matrix, the variance over all 22 * elements will be calculated. 23 * 24 * Additionally, it is possible to compute the variance along the rows 25 * or columns of a matrix by specifying the dimension as the second argument. 26 * 27 * Optionally, the type of normalization can be specified as the final 28 * parameter. The parameter `normalization` can be one of the following values: 29 * 30 * - 'unbiased' (default) The sum of squared errors is divided by (n - 1) 31 * - 'uncorrected' The sum of squared errors is divided by n 32 * - 'biased' The sum of squared errors is divided by (n + 1) 33 * 34 * 35 * Note that older browser may not like the variable name `var`. In that 36 * case, the function can be called as `math['var'](...)` instead of 37 * `math.var(...)`. 38 * 39 * Syntax: 40 * 41 * math.variance(a, b, c, ...) 42 * math.variance(A) 43 * math.variance(A, normalization) 44 * math.variance(A, dimension) 45 * math.variance(A, dimension, normalization) 46 * 47 * Examples: 48 * 49 * math.variance(2, 4, 6) // returns 4 50 * math.variance([2, 4, 6, 8]) // returns 6.666666666666667 51 * math.variance([2, 4, 6, 8], 'uncorrected') // returns 5 52 * math.variance([2, 4, 6, 8], 'biased') // returns 4 53 * 54 * math.variance([[1, 2, 3], [4, 5, 6]]) // returns 3.5 55 * math.variance([[1, 2, 3], [4, 6, 8]], 0) // returns [4.5, 8, 12.5] 56 * math.variance([[1, 2, 3], [4, 6, 8]], 1) // returns [1, 4] 57 * math.variance([[1, 2, 3], [4, 6, 8]], 1, 'biased') // returns [0.5, 2] 58 * 59 * See also: 60 * 61 * mean, median, max, min, prod, std, sum 62 * 63 * @param {Array | Matrix} array 64 * A single matrix or or multiple scalar values 65 * @param {string} [normalization='unbiased'] 66 * Determines how to normalize the variance. 67 * Choose 'unbiased' (default), 'uncorrected', or 'biased'. 68 * @param dimension {number | BigNumber} 69 * Determines the axis to compute the variance for a matrix 70 * @return {*} The variance 71 */ 72 return typed(name, { 73 // variance([a, b, c, d, ...]) 74 'Array | Matrix': function ArrayMatrix(array) { 75 return _var(array, DEFAULT_NORMALIZATION); 76 }, 77 // variance([a, b, c, d, ...], normalization) 78 'Array | Matrix, string': _var, 79 // variance([a, b, c, c, ...], dim) 80 'Array | Matrix, number | BigNumber': function ArrayMatrixNumberBigNumber(array, dim) { 81 return _varDim(array, dim, DEFAULT_NORMALIZATION); 82 }, 83 // variance([a, b, c, c, ...], dim, normalization) 84 'Array | Matrix, number | BigNumber, string': _varDim, 85 // variance(a, b, c, d, ...) 86 '...': function _(args) { 87 return _var(args, DEFAULT_NORMALIZATION); 88 } 89 }); 90 /** 91 * Recursively calculate the variance of an n-dimensional array 92 * @param {Array} array 93 * @param {string} normalization 94 * Determines how to normalize the variance: 95 * - 'unbiased' The sum of squared errors is divided by (n - 1) 96 * - 'uncorrected' The sum of squared errors is divided by n 97 * - 'biased' The sum of squared errors is divided by (n + 1) 98 * @return {number | BigNumber} variance 99 * @private 100 */ 101 102 function _var(array, normalization) { 103 var sum; 104 var num = 0; 105 106 if (array.length === 0) { 107 throw new SyntaxError('Function variance requires one or more parameters (0 provided)'); 108 } // calculate the mean and number of elements 109 110 111 deepForEach(array, function (value) { 112 try { 113 sum = sum === undefined ? value : add(sum, value); 114 num++; 115 } catch (err) { 116 throw improveErrorMessage(err, 'variance', value); 117 } 118 }); 119 if (num === 0) throw new Error('Cannot calculate variance of an empty array'); 120 var mean = divide(sum, num); // calculate the variance 121 122 sum = undefined; 123 deepForEach(array, function (value) { 124 var diff = subtract(value, mean); 125 sum = sum === undefined ? multiply(diff, diff) : add(sum, multiply(diff, diff)); 126 }); 127 128 if (isNaN(sum)) { 129 return sum; 130 } 131 132 switch (normalization) { 133 case 'uncorrected': 134 return divide(sum, num); 135 136 case 'biased': 137 return divide(sum, num + 1); 138 139 case 'unbiased': 140 { 141 var zero = isBigNumber(sum) ? sum.mul(0) : 0; 142 return num === 1 ? zero : divide(sum, num - 1); 143 } 144 145 default: 146 throw new Error('Unknown normalization "' + normalization + '". ' + 'Choose "unbiased" (default), "uncorrected", or "biased".'); 147 } 148 } 149 150 function _varDim(array, dim, normalization) { 151 try { 152 if (array.length === 0) { 153 throw new SyntaxError('Function variance requires one or more parameters (0 provided)'); 154 } 155 156 return apply(array, dim, x => _var(x, normalization)); 157 } catch (err) { 158 throw improveErrorMessage(err, 'variance'); 159 } 160 } 161 });