vector.js (14870B)
1 (function(jStat, Math) { 2 3 var isFunction = jStat.utils.isFunction; 4 5 // Ascending functions for sort 6 function ascNum(a, b) { return a - b; } 7 8 function clip(arg, min, max) { 9 return Math.max(min, Math.min(arg, max)); 10 } 11 12 13 // sum of an array 14 jStat.sum = function sum(arr) { 15 var sum = 0; 16 var i = arr.length; 17 while (--i >= 0) 18 sum += arr[i]; 19 return sum; 20 }; 21 22 23 // sum squared 24 jStat.sumsqrd = function sumsqrd(arr) { 25 var sum = 0; 26 var i = arr.length; 27 while (--i >= 0) 28 sum += arr[i] * arr[i]; 29 return sum; 30 }; 31 32 33 // sum of squared errors of prediction (SSE) 34 jStat.sumsqerr = function sumsqerr(arr) { 35 var mean = jStat.mean(arr); 36 var sum = 0; 37 var i = arr.length; 38 var tmp; 39 while (--i >= 0) { 40 tmp = arr[i] - mean; 41 sum += tmp * tmp; 42 } 43 return sum; 44 }; 45 46 // sum of an array in each row 47 jStat.sumrow = function sumrow(arr) { 48 var sum = 0; 49 var i = arr.length; 50 while (--i >= 0) 51 sum += arr[i]; 52 return sum; 53 }; 54 55 // product of an array 56 jStat.product = function product(arr) { 57 var prod = 1; 58 var i = arr.length; 59 while (--i >= 0) 60 prod *= arr[i]; 61 return prod; 62 }; 63 64 65 // minimum value of an array 66 jStat.min = function min(arr) { 67 var low = arr[0]; 68 var i = 0; 69 while (++i < arr.length) 70 if (arr[i] < low) 71 low = arr[i]; 72 return low; 73 }; 74 75 76 // maximum value of an array 77 jStat.max = function max(arr) { 78 var high = arr[0]; 79 var i = 0; 80 while (++i < arr.length) 81 if (arr[i] > high) 82 high = arr[i]; 83 return high; 84 }; 85 86 87 // unique values of an array 88 jStat.unique = function unique(arr) { 89 var hash = {}, _arr = []; 90 for(var i = 0; i < arr.length; i++) { 91 if (!hash[arr[i]]) { 92 hash[arr[i]] = true; 93 _arr.push(arr[i]); 94 } 95 } 96 return _arr; 97 }; 98 99 100 // mean value of an array 101 jStat.mean = function mean(arr) { 102 return jStat.sum(arr) / arr.length; 103 }; 104 105 106 // mean squared error (MSE) 107 jStat.meansqerr = function meansqerr(arr) { 108 return jStat.sumsqerr(arr) / arr.length; 109 }; 110 111 112 // geometric mean of an array 113 jStat.geomean = function geomean(arr) { 114 var logs = arr.map(Math.log) 115 var meanOfLogs = jStat.mean(logs) 116 return Math.exp(meanOfLogs) 117 }; 118 119 120 // median of an array 121 jStat.median = function median(arr) { 122 var arrlen = arr.length; 123 var _arr = arr.slice().sort(ascNum); 124 // check if array is even or odd, then return the appropriate 125 return !(arrlen & 1) 126 ? (_arr[(arrlen / 2) - 1 ] + _arr[(arrlen / 2)]) / 2 127 : _arr[(arrlen / 2) | 0 ]; 128 }; 129 130 131 // cumulative sum of an array 132 jStat.cumsum = function cumsum(arr) { 133 return jStat.cumreduce(arr, function (a, b) { return a + b; }); 134 }; 135 136 137 // cumulative product of an array 138 jStat.cumprod = function cumprod(arr) { 139 return jStat.cumreduce(arr, function (a, b) { return a * b; }); 140 }; 141 142 143 // successive differences of a sequence 144 jStat.diff = function diff(arr) { 145 var diffs = []; 146 var arrLen = arr.length; 147 var i; 148 for (i = 1; i < arrLen; i++) 149 diffs.push(arr[i] - arr[i - 1]); 150 return diffs; 151 }; 152 153 154 // ranks of an array 155 jStat.rank = function (arr) { 156 var i; 157 var distinctNumbers = []; 158 var numberCounts = {}; 159 for (i = 0; i < arr.length; i++) { 160 var number = arr[i]; 161 if (numberCounts[number]) { 162 numberCounts[number]++; 163 } else { 164 numberCounts[number] = 1; 165 distinctNumbers.push(number); 166 } 167 } 168 169 var sortedDistinctNumbers = distinctNumbers.sort(ascNum); 170 var numberRanks = {}; 171 var currentRank = 1; 172 for (i = 0; i < sortedDistinctNumbers.length; i++) { 173 var number = sortedDistinctNumbers[i]; 174 var count = numberCounts[number]; 175 var first = currentRank; 176 var last = currentRank + count - 1; 177 var rank = (first + last) / 2; 178 numberRanks[number] = rank; 179 currentRank += count; 180 } 181 182 return arr.map(function (number) { 183 return numberRanks[number]; 184 }); 185 }; 186 187 188 // mode of an array 189 // if there are multiple modes of an array, return all of them 190 // is this the appropriate way of handling it? 191 jStat.mode = function mode(arr) { 192 var arrLen = arr.length; 193 var _arr = arr.slice().sort(ascNum); 194 var count = 1; 195 var maxCount = 0; 196 var numMaxCount = 0; 197 var mode_arr = []; 198 var i; 199 200 for (i = 0; i < arrLen; i++) { 201 if (_arr[i] === _arr[i + 1]) { 202 count++; 203 } else { 204 if (count > maxCount) { 205 mode_arr = [_arr[i]]; 206 maxCount = count; 207 numMaxCount = 0; 208 } 209 // are there multiple max counts 210 else if (count === maxCount) { 211 mode_arr.push(_arr[i]); 212 numMaxCount++; 213 } 214 // resetting count for new value in array 215 count = 1; 216 } 217 } 218 219 return numMaxCount === 0 ? mode_arr[0] : mode_arr; 220 }; 221 222 223 // range of an array 224 jStat.range = function range(arr) { 225 return jStat.max(arr) - jStat.min(arr); 226 }; 227 228 // variance of an array 229 // flag = true indicates sample instead of population 230 jStat.variance = function variance(arr, flag) { 231 return jStat.sumsqerr(arr) / (arr.length - (flag ? 1 : 0)); 232 }; 233 234 // pooled variance of an array of arrays 235 jStat.pooledvariance = function pooledvariance(arr) { 236 var sumsqerr = arr.reduce(function (a, samples) {return a + jStat.sumsqerr(samples);}, 0); 237 var count = arr.reduce(function (a, samples) {return a + samples.length;}, 0); 238 return sumsqerr / (count - arr.length); 239 }; 240 241 // deviation of an array 242 jStat.deviation = function (arr) { 243 var mean = jStat.mean(arr); 244 var arrlen = arr.length; 245 var dev = new Array(arrlen); 246 for (var i = 0; i < arrlen; i++) { 247 dev[i] = arr[i] - mean; 248 } 249 return dev; 250 }; 251 252 // standard deviation of an array 253 // flag = true indicates sample instead of population 254 jStat.stdev = function stdev(arr, flag) { 255 return Math.sqrt(jStat.variance(arr, flag)); 256 }; 257 258 // pooled standard deviation of an array of arrays 259 jStat.pooledstdev = function pooledstdev(arr) { 260 return Math.sqrt(jStat.pooledvariance(arr)); 261 }; 262 263 // mean deviation (mean absolute deviation) of an array 264 jStat.meandev = function meandev(arr) { 265 var mean = jStat.mean(arr); 266 var a = []; 267 for (var i = arr.length - 1; i >= 0; i--) { 268 a.push(Math.abs(arr[i] - mean)); 269 } 270 return jStat.mean(a); 271 }; 272 273 274 // median deviation (median absolute deviation) of an array 275 jStat.meddev = function meddev(arr) { 276 var median = jStat.median(arr); 277 var a = []; 278 for (var i = arr.length - 1; i >= 0; i--) { 279 a.push(Math.abs(arr[i] - median)); 280 } 281 return jStat.median(a); 282 }; 283 284 285 // coefficient of variation 286 jStat.coeffvar = function coeffvar(arr) { 287 return jStat.stdev(arr) / jStat.mean(arr); 288 }; 289 290 291 // quartiles of an array 292 jStat.quartiles = function quartiles(arr) { 293 var arrlen = arr.length; 294 var _arr = arr.slice().sort(ascNum); 295 return [ 296 _arr[ Math.round((arrlen) / 4) - 1 ], 297 _arr[ Math.round((arrlen) / 2) - 1 ], 298 _arr[ Math.round((arrlen) * 3 / 4) - 1 ] 299 ]; 300 }; 301 302 303 // Arbitary quantiles of an array. Direct port of the scipy.stats 304 // implementation by Pierre GF Gerard-Marchant. 305 jStat.quantiles = function quantiles(arr, quantilesArray, alphap, betap) { 306 var sortedArray = arr.slice().sort(ascNum); 307 var quantileVals = [quantilesArray.length]; 308 var n = arr.length; 309 var i, p, m, aleph, k, gamma; 310 311 if (typeof alphap === 'undefined') 312 alphap = 3 / 8; 313 if (typeof betap === 'undefined') 314 betap = 3 / 8; 315 316 for (i = 0; i < quantilesArray.length; i++) { 317 p = quantilesArray[i]; 318 m = alphap + p * (1 - alphap - betap); 319 aleph = n * p + m; 320 k = Math.floor(clip(aleph, 1, n - 1)); 321 gamma = clip(aleph - k, 0, 1); 322 quantileVals[i] = (1 - gamma) * sortedArray[k - 1] + gamma * sortedArray[k]; 323 } 324 325 return quantileVals; 326 }; 327 328 // Return the k-th percentile of values in a range, where k is in the range 0..1, inclusive. 329 // Passing true for the exclusive parameter excludes both endpoints of the range. 330 jStat.percentile = function percentile(arr, k, exclusive) { 331 var _arr = arr.slice().sort(ascNum); 332 var realIndex = k * (_arr.length + (exclusive ? 1 : -1)) + (exclusive ? 0 : 1); 333 var index = parseInt(realIndex); 334 var frac = realIndex - index; 335 if (index + 1 < _arr.length) { 336 return _arr[index - 1] + frac * (_arr[index] - _arr[index - 1]); 337 } else { 338 return _arr[index - 1]; 339 } 340 } 341 342 // The percentile rank of score in a given array. Returns the percentage 343 // of all values in the input array that are less than (kind='strict') or 344 // less or equal than (kind='weak') score. Default is weak. 345 jStat.percentileOfScore = function percentileOfScore(arr, score, kind) { 346 var counter = 0; 347 var len = arr.length; 348 var strict = false; 349 var value, i; 350 351 if (kind === 'strict') 352 strict = true; 353 354 for (i = 0; i < len; i++) { 355 value = arr[i]; 356 if ((strict && value < score) || 357 (!strict && value <= score)) { 358 counter++; 359 } 360 } 361 362 return counter / len; 363 }; 364 365 366 // Histogram (bin count) data 367 jStat.histogram = function histogram(arr, binCnt) { 368 binCnt = binCnt || 4; 369 var first = jStat.min(arr); 370 var binWidth = (jStat.max(arr) - first) / binCnt; 371 var len = arr.length; 372 var bins = []; 373 var i; 374 375 for (i = 0; i < binCnt; i++) 376 bins[i] = 0; 377 for (i = 0; i < len; i++) 378 bins[Math.min(Math.floor(((arr[i] - first) / binWidth)), binCnt - 1)] += 1; 379 380 return bins; 381 }; 382 383 384 // covariance of two arrays 385 jStat.covariance = function covariance(arr1, arr2) { 386 var u = jStat.mean(arr1); 387 var v = jStat.mean(arr2); 388 var arr1Len = arr1.length; 389 var sq_dev = new Array(arr1Len); 390 var i; 391 392 for (i = 0; i < arr1Len; i++) 393 sq_dev[i] = (arr1[i] - u) * (arr2[i] - v); 394 395 return jStat.sum(sq_dev) / (arr1Len - 1); 396 }; 397 398 399 // (pearson's) population correlation coefficient, rho 400 jStat.corrcoeff = function corrcoeff(arr1, arr2) { 401 return jStat.covariance(arr1, arr2) / 402 jStat.stdev(arr1, 1) / 403 jStat.stdev(arr2, 1); 404 }; 405 406 // (spearman's) rank correlation coefficient, sp 407 jStat.spearmancoeff = function (arr1, arr2) { 408 arr1 = jStat.rank(arr1); 409 arr2 = jStat.rank(arr2); 410 //return pearson's correlation of the ranks: 411 return jStat.corrcoeff(arr1, arr2); 412 } 413 414 415 // statistical standardized moments (general form of skew/kurt) 416 jStat.stanMoment = function stanMoment(arr, n) { 417 var mu = jStat.mean(arr); 418 var sigma = jStat.stdev(arr); 419 var len = arr.length; 420 var skewSum = 0; 421 422 for (var i = 0; i < len; i++) 423 skewSum += Math.pow((arr[i] - mu) / sigma, n); 424 425 return skewSum / arr.length; 426 }; 427 428 // (pearson's) moment coefficient of skewness 429 jStat.skewness = function skewness(arr) { 430 return jStat.stanMoment(arr, 3); 431 }; 432 433 // (pearson's) (excess) kurtosis 434 jStat.kurtosis = function kurtosis(arr) { 435 return jStat.stanMoment(arr, 4) - 3; 436 }; 437 438 439 var jProto = jStat.prototype; 440 441 442 // Extend jProto with method for calculating cumulative sums and products. 443 // This differs from the similar extension below as cumsum and cumprod should 444 // not be run again in the case fullbool === true. 445 // If a matrix is passed, automatically assume operation should be done on the 446 // columns. 447 (function(funcs) { 448 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 449 // If a matrix is passed, automatically assume operation should be done on 450 // the columns. 451 jProto[passfunc] = function(fullbool, func) { 452 var arr = []; 453 var i = 0; 454 var tmpthis = this; 455 // Assignment reassignation depending on how parameters were passed in. 456 if (isFunction(fullbool)) { 457 func = fullbool; 458 fullbool = false; 459 } 460 // Check if a callback was passed with the function. 461 if (func) { 462 setTimeout(function() { 463 func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool)); 464 }); 465 return this; 466 } 467 // Check if matrix and run calculations. 468 if (this.length > 1) { 469 tmpthis = fullbool === true ? this : this.transpose(); 470 for (; i < tmpthis.length; i++) 471 arr[i] = jStat[passfunc](tmpthis[i]); 472 return arr; 473 } 474 // Pass fullbool if only vector, not a matrix. for variance and stdev. 475 return jStat[passfunc](this[0], fullbool); 476 }; 477 })(funcs[i]); 478 })(('cumsum cumprod').split(' ')); 479 480 481 // Extend jProto with methods which don't require arguments and work on columns. 482 (function(funcs) { 483 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 484 // If a matrix is passed, automatically assume operation should be done on 485 // the columns. 486 jProto[passfunc] = function(fullbool, func) { 487 var arr = []; 488 var i = 0; 489 var tmpthis = this; 490 // Assignment reassignation depending on how parameters were passed in. 491 if (isFunction(fullbool)) { 492 func = fullbool; 493 fullbool = false; 494 } 495 // Check if a callback was passed with the function. 496 if (func) { 497 setTimeout(function() { 498 func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool)); 499 }); 500 return this; 501 } 502 // Check if matrix and run calculations. 503 if (this.length > 1) { 504 if (passfunc !== 'sumrow') 505 tmpthis = fullbool === true ? this : this.transpose(); 506 for (; i < tmpthis.length; i++) 507 arr[i] = jStat[passfunc](tmpthis[i]); 508 return fullbool === true 509 ? jStat[passfunc](jStat.utils.toVector(arr)) 510 : arr; 511 } 512 // Pass fullbool if only vector, not a matrix. for variance and stdev. 513 return jStat[passfunc](this[0], fullbool); 514 }; 515 })(funcs[i]); 516 })(('sum sumsqrd sumsqerr sumrow product min max unique mean meansqerr ' + 517 'geomean median diff rank mode range variance deviation stdev meandev ' + 518 'meddev coeffvar quartiles histogram skewness kurtosis').split(' ')); 519 520 521 // Extend jProto with functions that take arguments. Operations on matrices are 522 // done on columns. 523 (function(funcs) { 524 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 525 jProto[passfunc] = function() { 526 var arr = []; 527 var i = 0; 528 var tmpthis = this; 529 var args = Array.prototype.slice.call(arguments); 530 var callbackFunction; 531 532 // If the last argument is a function, we assume it's a callback; we 533 // strip the callback out and call the function again. 534 if (isFunction(args[args.length - 1])) { 535 callbackFunction = args[args.length - 1]; 536 var argsToPass = args.slice(0, args.length - 1); 537 538 setTimeout(function() { 539 callbackFunction.call(tmpthis, 540 jProto[passfunc].apply(tmpthis, argsToPass)); 541 }); 542 return this; 543 544 // Otherwise we curry the function args and call normally. 545 } else { 546 callbackFunction = undefined; 547 var curriedFunction = function curriedFunction(vector) { 548 return jStat[passfunc].apply(tmpthis, [vector].concat(args)); 549 } 550 } 551 552 // If this is a matrix, run column-by-column. 553 if (this.length > 1) { 554 tmpthis = tmpthis.transpose(); 555 for (; i < tmpthis.length; i++) 556 arr[i] = curriedFunction(tmpthis[i]); 557 return arr; 558 } 559 560 // Otherwise run on the vector. 561 return curriedFunction(this[0]); 562 }; 563 })(funcs[i]); 564 })('quantiles percentileOfScore'.split(' ')); 565 566 }(jStat, Math));