quantileSeq.js (8615B)
1 import { isBigNumber, isCollection, isNumber } from '../../utils/is.js'; 2 import { isInteger } from '../../utils/number.js'; 3 import { flatten } from '../../utils/array.js'; 4 import { factory } from '../../utils/factory.js'; 5 var name = 'quantileSeq'; 6 var dependencies = ['typed', 'add', 'multiply', 'partitionSelect', 'compare']; 7 export var createQuantileSeq = /* #__PURE__ */factory(name, dependencies, _ref => { 8 var { 9 typed, 10 add, 11 multiply, 12 partitionSelect, 13 compare 14 } = _ref; 15 16 /** 17 * Compute the prob order quantile of a matrix or a list with values. 18 * The sequence is sorted and the middle value is returned. 19 * Supported types of sequence values are: Number, BigNumber, Unit 20 * Supported types of probability are: Number, BigNumber 21 * 22 * In case of a (multi dimensional) array or matrix, the prob order quantile 23 * of all elements will be calculated. 24 * 25 * Syntax: 26 * 27 * math.quantileSeq(A, prob[, sorted]) 28 * math.quantileSeq(A, [prob1, prob2, ...][, sorted]) 29 * math.quantileSeq(A, N[, sorted]) 30 * 31 * Examples: 32 * 33 * math.quantileSeq([3, -1, 5, 7], 0.5) // returns 4 34 * math.quantileSeq([3, -1, 5, 7], [1/3, 2/3]) // returns [3, 5] 35 * math.quantileSeq([3, -1, 5, 7], 2) // returns [3, 5] 36 * math.quantileSeq([-1, 3, 5, 7], 0.5, true) // returns 4 37 * 38 * See also: 39 * 40 * median, mean, min, max, sum, prod, std, variance 41 * 42 * @param {Array, Matrix} data A single matrix or Array 43 * @param {Number, BigNumber, Array} probOrN prob is the order of the quantile, while N is 44 * the amount of evenly distributed steps of 45 * probabilities; only one of these options can 46 * be provided 47 * @param {Boolean} sorted=false is data sorted in ascending order 48 * @return {Number, BigNumber, Unit, Array} Quantile(s) 49 */ 50 function quantileSeq(data, probOrN, sorted) { 51 var probArr, dataArr, one; 52 53 if (arguments.length < 2 || arguments.length > 3) { 54 throw new SyntaxError('Function quantileSeq requires two or three parameters'); 55 } 56 57 if (isCollection(data)) { 58 sorted = sorted || false; 59 60 if (typeof sorted === 'boolean') { 61 dataArr = data.valueOf(); 62 63 if (isNumber(probOrN)) { 64 if (probOrN < 0) { 65 throw new Error('N/prob must be non-negative'); 66 } 67 68 if (probOrN <= 1) { 69 // quantileSeq([a, b, c, d, ...], prob[,sorted]) 70 return _quantileSeq(dataArr, probOrN, sorted); 71 } 72 73 if (probOrN > 1) { 74 // quantileSeq([a, b, c, d, ...], N[,sorted]) 75 if (!isInteger(probOrN)) { 76 throw new Error('N must be a positive integer'); 77 } 78 79 var nPlusOne = probOrN + 1; 80 probArr = new Array(probOrN); 81 82 for (var i = 0; i < probOrN;) { 83 probArr[i] = _quantileSeq(dataArr, ++i / nPlusOne, sorted); 84 } 85 86 return probArr; 87 } 88 } 89 90 if (isBigNumber(probOrN)) { 91 var BigNumber = probOrN.constructor; 92 93 if (probOrN.isNegative()) { 94 throw new Error('N/prob must be non-negative'); 95 } 96 97 one = new BigNumber(1); 98 99 if (probOrN.lte(one)) { 100 // quantileSeq([a, b, c, d, ...], prob[,sorted]) 101 return new BigNumber(_quantileSeq(dataArr, probOrN, sorted)); 102 } 103 104 if (probOrN.gt(one)) { 105 // quantileSeq([a, b, c, d, ...], N[,sorted]) 106 if (!probOrN.isInteger()) { 107 throw new Error('N must be a positive integer'); 108 } // largest possible Array length is 2^32-1 109 // 2^32 < 10^15, thus safe conversion guaranteed 110 111 112 var intN = probOrN.toNumber(); 113 114 if (intN > 4294967295) { 115 throw new Error('N must be less than or equal to 2^32-1, as that is the maximum length of an Array'); 116 } 117 118 var _nPlusOne = new BigNumber(intN + 1); 119 120 probArr = new Array(intN); 121 122 for (var _i = 0; _i < intN;) { 123 probArr[_i] = new BigNumber(_quantileSeq(dataArr, new BigNumber(++_i).div(_nPlusOne), sorted)); 124 } 125 126 return probArr; 127 } 128 } 129 130 if (Array.isArray(probOrN)) { 131 // quantileSeq([a, b, c, d, ...], [prob1, prob2, ...][,sorted]) 132 probArr = new Array(probOrN.length); 133 134 for (var _i2 = 0; _i2 < probArr.length; ++_i2) { 135 var currProb = probOrN[_i2]; 136 137 if (isNumber(currProb)) { 138 if (currProb < 0 || currProb > 1) { 139 throw new Error('Probability must be between 0 and 1, inclusive'); 140 } 141 } else if (isBigNumber(currProb)) { 142 one = new currProb.constructor(1); 143 144 if (currProb.isNegative() || currProb.gt(one)) { 145 throw new Error('Probability must be between 0 and 1, inclusive'); 146 } 147 } else { 148 throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function 149 } 150 151 probArr[_i2] = _quantileSeq(dataArr, currProb, sorted); 152 } 153 154 return probArr; 155 } 156 157 throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function 158 } 159 160 throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function 161 } 162 163 throw new TypeError('Unexpected type of argument in function quantileSeq'); // FIXME: becomes redundant when converted to typed-function 164 } 165 /** 166 * Calculate the prob order quantile of an n-dimensional array. 167 * 168 * @param {Array} array 169 * @param {Number, BigNumber} prob 170 * @param {Boolean} sorted 171 * @return {Number, BigNumber, Unit} prob order quantile 172 * @private 173 */ 174 175 176 function _quantileSeq(array, prob, sorted) { 177 var flat = flatten(array); 178 var len = flat.length; 179 180 if (len === 0) { 181 throw new Error('Cannot calculate quantile of an empty sequence'); 182 } 183 184 if (isNumber(prob)) { 185 var _index = prob * (len - 1); 186 187 var _fracPart = _index % 1; 188 189 if (_fracPart === 0) { 190 var value = sorted ? flat[_index] : partitionSelect(flat, _index); 191 validate(value); 192 return value; 193 } 194 195 var _integerPart = Math.floor(_index); 196 197 var _left; 198 199 var _right; 200 201 if (sorted) { 202 _left = flat[_integerPart]; 203 _right = flat[_integerPart + 1]; 204 } else { 205 _right = partitionSelect(flat, _integerPart + 1); // max of partition is kth largest 206 207 _left = flat[_integerPart]; 208 209 for (var i = 0; i < _integerPart; ++i) { 210 if (compare(flat[i], _left) > 0) { 211 _left = flat[i]; 212 } 213 } 214 } 215 216 validate(_left); 217 validate(_right); // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] 218 219 return add(multiply(_left, 1 - _fracPart), multiply(_right, _fracPart)); 220 } // If prob is a BigNumber 221 222 223 var index = prob.times(len - 1); 224 225 if (index.isInteger()) { 226 index = index.toNumber(); 227 228 var _value = sorted ? flat[index] : partitionSelect(flat, index); 229 230 validate(_value); 231 return _value; 232 } 233 234 var integerPart = index.floor(); 235 var fracPart = index.minus(integerPart); 236 var integerPartNumber = integerPart.toNumber(); 237 var left; 238 var right; 239 240 if (sorted) { 241 left = flat[integerPartNumber]; 242 right = flat[integerPartNumber + 1]; 243 } else { 244 right = partitionSelect(flat, integerPartNumber + 1); // max of partition is kth largest 245 246 left = flat[integerPartNumber]; 247 248 for (var _i3 = 0; _i3 < integerPartNumber; ++_i3) { 249 if (compare(flat[_i3], left) > 0) { 250 left = flat[_i3]; 251 } 252 } 253 } 254 255 validate(left); 256 validate(right); // Q(prob) = (1-f)*A[floor(index)] + f*A[floor(index)+1] 257 258 var one = new fracPart.constructor(1); 259 return add(multiply(left, one.minus(fracPart)), multiply(right, fracPart)); 260 } 261 /** 262 * Check if array value types are valid, throw error otherwise. 263 * @param {number | BigNumber | Unit} x 264 * @param {number | BigNumber | Unit} x 265 * @private 266 */ 267 268 269 var validate = typed({ 270 'number | BigNumber | Unit': function numberBigNumberUnit(x) { 271 return x; 272 } 273 }); 274 return quantileSeq; 275 });