jstat.js (129959B)
1 (function (window, factory) { 2 if (typeof exports === 'object') { 3 module.exports = factory(); 4 } else if (typeof define === 'function' && define.amd) { 5 define(factory); 6 } else { 7 window.jStat = factory(); 8 } 9 })(this, function () { 10 var jStat = (function(Math, undefined) { 11 12 // For quick reference. 13 var concat = Array.prototype.concat; 14 var slice = Array.prototype.slice; 15 var toString = Object.prototype.toString; 16 17 // Calculate correction for IEEE error 18 // TODO: This calculation can be improved. 19 function calcRdx(n, m) { 20 var val = n > m ? n : m; 21 return Math.pow(10, 22 17 - ~~(Math.log(((val > 0) ? val : -val)) * Math.LOG10E)); 23 } 24 25 26 var isArray = Array.isArray || function isArray(arg) { 27 return toString.call(arg) === '[object Array]'; 28 }; 29 30 31 function isFunction(arg) { 32 return toString.call(arg) === '[object Function]'; 33 } 34 35 36 function isNumber(num) { 37 return (typeof num === 'number') ? num - num === 0 : false; 38 } 39 40 41 // Converts the jStat matrix to vector. 42 function toVector(arr) { 43 return concat.apply([], arr); 44 } 45 46 47 // The one and only jStat constructor. 48 function jStat() { 49 return new jStat._init(arguments); 50 } 51 52 53 // TODO: Remove after all references in src files have been removed. 54 jStat.fn = jStat.prototype; 55 56 57 // By separating the initializer from the constructor it's easier to handle 58 // always returning a new instance whether "new" was used or not. 59 jStat._init = function _init(args) { 60 // If first argument is an array, must be vector or matrix. 61 if (isArray(args[0])) { 62 // Check if matrix. 63 if (isArray(args[0][0])) { 64 // See if a mapping function was also passed. 65 if (isFunction(args[1])) 66 args[0] = jStat.map(args[0], args[1]); 67 // Iterate over each is faster than this.push.apply(this, args[0]. 68 for (var i = 0; i < args[0].length; i++) 69 this[i] = args[0][i]; 70 this.length = args[0].length; 71 72 // Otherwise must be a vector. 73 } else { 74 this[0] = isFunction(args[1]) ? jStat.map(args[0], args[1]) : args[0]; 75 this.length = 1; 76 } 77 78 // If first argument is number, assume creation of sequence. 79 } else if (isNumber(args[0])) { 80 this[0] = jStat.seq.apply(null, args); 81 this.length = 1; 82 83 // Handle case when jStat object is passed to jStat. 84 } else if (args[0] instanceof jStat) { 85 // Duplicate the object and pass it back. 86 return jStat(args[0].toArray()); 87 88 // Unexpected argument value, return empty jStat object. 89 // TODO: This is strange behavior. Shouldn't this throw or some such to let 90 // the user know they had bad arguments? 91 } else { 92 this[0] = []; 93 this.length = 1; 94 } 95 96 return this; 97 }; 98 jStat._init.prototype = jStat.prototype; 99 jStat._init.constructor = jStat; 100 101 102 // Utility functions. 103 // TODO: for internal use only? 104 jStat.utils = { 105 calcRdx: calcRdx, 106 isArray: isArray, 107 isFunction: isFunction, 108 isNumber: isNumber, 109 toVector: toVector 110 }; 111 112 113 jStat._random_fn = Math.random; 114 jStat.setRandom = function setRandom(fn) { 115 if (typeof fn !== 'function') 116 throw new TypeError('fn is not a function'); 117 jStat._random_fn = fn; 118 }; 119 120 121 // Easily extend the jStat object. 122 // TODO: is this seriously necessary? 123 jStat.extend = function extend(obj) { 124 var i, j; 125 126 if (arguments.length === 1) { 127 for (j in obj) 128 jStat[j] = obj[j]; 129 return this; 130 } 131 132 for (i = 1; i < arguments.length; i++) { 133 for (j in arguments[i]) 134 obj[j] = arguments[i][j]; 135 } 136 137 return obj; 138 }; 139 140 141 // Returns the number of rows in the matrix. 142 jStat.rows = function rows(arr) { 143 return arr.length || 1; 144 }; 145 146 147 // Returns the number of columns in the matrix. 148 jStat.cols = function cols(arr) { 149 return arr[0].length || 1; 150 }; 151 152 153 // Returns the dimensions of the object { rows: i, cols: j } 154 jStat.dimensions = function dimensions(arr) { 155 return { 156 rows: jStat.rows(arr), 157 cols: jStat.cols(arr) 158 }; 159 }; 160 161 162 // Returns a specified row as a vector or return a sub matrix by pick some rows 163 jStat.row = function row(arr, index) { 164 if (isArray(index)) { 165 return index.map(function(i) { 166 return jStat.row(arr, i); 167 }) 168 } 169 return arr[index]; 170 }; 171 172 173 // return row as array 174 // rowa([[1,2],[3,4]],0) -> [1,2] 175 jStat.rowa = function rowa(arr, i) { 176 return jStat.row(arr, i); 177 }; 178 179 180 // Returns the specified column as a vector or return a sub matrix by pick some 181 // columns 182 jStat.col = function col(arr, index) { 183 if (isArray(index)) { 184 var submat = jStat.arange(arr.length).map(function() { 185 return new Array(index.length); 186 }); 187 index.forEach(function(ind, i){ 188 jStat.arange(arr.length).forEach(function(j) { 189 submat[j][i] = arr[j][ind]; 190 }); 191 }); 192 return submat; 193 } 194 var column = new Array(arr.length); 195 for (var i = 0; i < arr.length; i++) 196 column[i] = [arr[i][index]]; 197 return column; 198 }; 199 200 201 // return column as array 202 // cola([[1,2],[3,4]],0) -> [1,3] 203 jStat.cola = function cola(arr, i) { 204 return jStat.col(arr, i).map(function(a){ return a[0] }); 205 }; 206 207 208 // Returns the diagonal of the matrix 209 jStat.diag = function diag(arr) { 210 var nrow = jStat.rows(arr); 211 var res = new Array(nrow); 212 for (var row = 0; row < nrow; row++) 213 res[row] = [arr[row][row]]; 214 return res; 215 }; 216 217 218 // Returns the anti-diagonal of the matrix 219 jStat.antidiag = function antidiag(arr) { 220 var nrow = jStat.rows(arr) - 1; 221 var res = new Array(nrow); 222 for (var i = 0; nrow >= 0; nrow--, i++) 223 res[i] = [arr[i][nrow]]; 224 return res; 225 }; 226 227 // Transpose a matrix or array. 228 jStat.transpose = function transpose(arr) { 229 var obj = []; 230 var objArr, rows, cols, j, i; 231 232 // Make sure arr is in matrix format. 233 if (!isArray(arr[0])) 234 arr = [arr]; 235 236 rows = arr.length; 237 cols = arr[0].length; 238 239 for (i = 0; i < cols; i++) { 240 objArr = new Array(rows); 241 for (j = 0; j < rows; j++) 242 objArr[j] = arr[j][i]; 243 obj.push(objArr); 244 } 245 246 // If obj is vector, return only single array. 247 return obj.length === 1 ? obj[0] : obj; 248 }; 249 250 251 // Map a function to an array or array of arrays. 252 // "toAlter" is an internal variable. 253 jStat.map = function map(arr, func, toAlter) { 254 var row, nrow, ncol, res, col; 255 256 if (!isArray(arr[0])) 257 arr = [arr]; 258 259 nrow = arr.length; 260 ncol = arr[0].length; 261 res = toAlter ? arr : new Array(nrow); 262 263 for (row = 0; row < nrow; row++) { 264 // if the row doesn't exist, create it 265 if (!res[row]) 266 res[row] = new Array(ncol); 267 for (col = 0; col < ncol; col++) 268 res[row][col] = func(arr[row][col], row, col); 269 } 270 271 return res.length === 1 ? res[0] : res; 272 }; 273 274 275 // Cumulatively combine the elements of an array or array of arrays using a function. 276 jStat.cumreduce = function cumreduce(arr, func, toAlter) { 277 var row, nrow, ncol, res, col; 278 279 if (!isArray(arr[0])) 280 arr = [arr]; 281 282 nrow = arr.length; 283 ncol = arr[0].length; 284 res = toAlter ? arr : new Array(nrow); 285 286 for (row = 0; row < nrow; row++) { 287 // if the row doesn't exist, create it 288 if (!res[row]) 289 res[row] = new Array(ncol); 290 if (ncol > 0) 291 res[row][0] = arr[row][0]; 292 for (col = 1; col < ncol; col++) 293 res[row][col] = func(res[row][col-1], arr[row][col]); 294 } 295 return res.length === 1 ? res[0] : res; 296 }; 297 298 299 // Destructively alter an array. 300 jStat.alter = function alter(arr, func) { 301 return jStat.map(arr, func, true); 302 }; 303 304 305 // Generate a rows x cols matrix according to the supplied function. 306 jStat.create = function create(rows, cols, func) { 307 var res = new Array(rows); 308 var i, j; 309 310 if (isFunction(cols)) { 311 func = cols; 312 cols = rows; 313 } 314 315 for (i = 0; i < rows; i++) { 316 res[i] = new Array(cols); 317 for (j = 0; j < cols; j++) 318 res[i][j] = func(i, j); 319 } 320 321 return res; 322 }; 323 324 325 function retZero() { return 0; } 326 327 328 // Generate a rows x cols matrix of zeros. 329 jStat.zeros = function zeros(rows, cols) { 330 if (!isNumber(cols)) 331 cols = rows; 332 return jStat.create(rows, cols, retZero); 333 }; 334 335 336 function retOne() { return 1; } 337 338 339 // Generate a rows x cols matrix of ones. 340 jStat.ones = function ones(rows, cols) { 341 if (!isNumber(cols)) 342 cols = rows; 343 return jStat.create(rows, cols, retOne); 344 }; 345 346 347 // Generate a rows x cols matrix of uniformly random numbers. 348 jStat.rand = function rand(rows, cols) { 349 if (!isNumber(cols)) 350 cols = rows; 351 return jStat.create(rows, cols, jStat._random_fn); 352 }; 353 354 355 function retIdent(i, j) { return i === j ? 1 : 0; } 356 357 358 // Generate an identity matrix of size row x cols. 359 jStat.identity = function identity(rows, cols) { 360 if (!isNumber(cols)) 361 cols = rows; 362 return jStat.create(rows, cols, retIdent); 363 }; 364 365 366 // Tests whether a matrix is symmetric 367 jStat.symmetric = function symmetric(arr) { 368 var size = arr.length; 369 var row, col; 370 371 if (arr.length !== arr[0].length) 372 return false; 373 374 for (row = 0; row < size; row++) { 375 for (col = 0; col < size; col++) 376 if (arr[col][row] !== arr[row][col]) 377 return false; 378 } 379 380 return true; 381 }; 382 383 384 // Set all values to zero. 385 jStat.clear = function clear(arr) { 386 return jStat.alter(arr, retZero); 387 }; 388 389 390 // Generate sequence. 391 jStat.seq = function seq(min, max, length, func) { 392 if (!isFunction(func)) 393 func = false; 394 395 var arr = []; 396 var hival = calcRdx(min, max); 397 var step = (max * hival - min * hival) / ((length - 1) * hival); 398 var current = min; 399 var cnt; 400 401 // Current is assigned using a technique to compensate for IEEE error. 402 // TODO: Needs better implementation. 403 for (cnt = 0; 404 current <= max && cnt < length; 405 cnt++, current = (min * hival + step * hival * cnt) / hival) { 406 arr.push((func ? func(current, cnt) : current)); 407 } 408 409 return arr; 410 }; 411 412 413 // arange(5) -> [0,1,2,3,4] 414 // arange(1,5) -> [1,2,3,4] 415 // arange(5,1,-1) -> [5,4,3,2] 416 jStat.arange = function arange(start, end, step) { 417 var rl = []; 418 var i; 419 step = step || 1; 420 if (end === undefined) { 421 end = start; 422 start = 0; 423 } 424 if (start === end || step === 0) { 425 return []; 426 } 427 if (start < end && step < 0) { 428 return []; 429 } 430 if (start > end && step > 0) { 431 return []; 432 } 433 if (step > 0) { 434 for (i = start; i < end; i += step) { 435 rl.push(i); 436 } 437 } else { 438 for (i = start; i > end; i += step) { 439 rl.push(i); 440 } 441 } 442 return rl; 443 }; 444 445 446 // A=[[1,2,3],[4,5,6],[7,8,9]] 447 // slice(A,{row:{end:2},col:{start:1}}) -> [[2,3],[5,6]] 448 // slice(A,1,{start:1}) -> [5,6] 449 // as numpy code A[:2,1:] 450 jStat.slice = (function(){ 451 function _slice(list, start, end, step) { 452 // note it's not equal to range.map mode it's a bug 453 var i; 454 var rl = []; 455 var length = list.length; 456 if (start === undefined && end === undefined && step === undefined) { 457 return jStat.copy(list); 458 } 459 460 start = start || 0; 461 end = end || list.length; 462 start = start >= 0 ? start : length + start; 463 end = end >= 0 ? end : length + end; 464 step = step || 1; 465 if (start === end || step === 0) { 466 return []; 467 } 468 if (start < end && step < 0) { 469 return []; 470 } 471 if (start > end && step > 0) { 472 return []; 473 } 474 if (step > 0) { 475 for (i = start; i < end; i += step) { 476 rl.push(list[i]); 477 } 478 } else { 479 for (i = start; i > end;i += step) { 480 rl.push(list[i]); 481 } 482 } 483 return rl; 484 } 485 486 function slice(list, rcSlice) { 487 var colSlice, rowSlice; 488 rcSlice = rcSlice || {}; 489 if (isNumber(rcSlice.row)) { 490 if (isNumber(rcSlice.col)) 491 return list[rcSlice.row][rcSlice.col]; 492 var row = jStat.rowa(list, rcSlice.row); 493 colSlice = rcSlice.col || {}; 494 return _slice(row, colSlice.start, colSlice.end, colSlice.step); 495 } 496 497 if (isNumber(rcSlice.col)) { 498 var col = jStat.cola(list, rcSlice.col); 499 rowSlice = rcSlice.row || {}; 500 return _slice(col, rowSlice.start, rowSlice.end, rowSlice.step); 501 } 502 503 rowSlice = rcSlice.row || {}; 504 colSlice = rcSlice.col || {}; 505 var rows = _slice(list, rowSlice.start, rowSlice.end, rowSlice.step); 506 return rows.map(function(row) { 507 return _slice(row, colSlice.start, colSlice.end, colSlice.step); 508 }); 509 } 510 511 return slice; 512 }()); 513 514 515 // A=[[1,2,3],[4,5,6],[7,8,9]] 516 // sliceAssign(A,{row:{start:1},col:{start:1}},[[0,0],[0,0]]) 517 // A=[[1,2,3],[4,0,0],[7,0,0]] 518 jStat.sliceAssign = function sliceAssign(A, rcSlice, B) { 519 var nl, ml; 520 if (isNumber(rcSlice.row)) { 521 if (isNumber(rcSlice.col)) 522 return A[rcSlice.row][rcSlice.col] = B; 523 rcSlice.col = rcSlice.col || {}; 524 rcSlice.col.start = rcSlice.col.start || 0; 525 rcSlice.col.end = rcSlice.col.end || A[0].length; 526 rcSlice.col.step = rcSlice.col.step || 1; 527 nl = jStat.arange(rcSlice.col.start, 528 Math.min(A.length, rcSlice.col.end), 529 rcSlice.col.step); 530 var m = rcSlice.row; 531 nl.forEach(function(n, i) { 532 A[m][n] = B[i]; 533 }); 534 return A; 535 } 536 537 if (isNumber(rcSlice.col)) { 538 rcSlice.row = rcSlice.row || {}; 539 rcSlice.row.start = rcSlice.row.start || 0; 540 rcSlice.row.end = rcSlice.row.end || A.length; 541 rcSlice.row.step = rcSlice.row.step || 1; 542 ml = jStat.arange(rcSlice.row.start, 543 Math.min(A[0].length, rcSlice.row.end), 544 rcSlice.row.step); 545 var n = rcSlice.col; 546 ml.forEach(function(m, j) { 547 A[m][n] = B[j]; 548 }); 549 return A; 550 } 551 552 if (B[0].length === undefined) { 553 B = [B]; 554 } 555 rcSlice.row.start = rcSlice.row.start || 0; 556 rcSlice.row.end = rcSlice.row.end || A.length; 557 rcSlice.row.step = rcSlice.row.step || 1; 558 rcSlice.col.start = rcSlice.col.start || 0; 559 rcSlice.col.end = rcSlice.col.end || A[0].length; 560 rcSlice.col.step = rcSlice.col.step || 1; 561 ml = jStat.arange(rcSlice.row.start, 562 Math.min(A.length, rcSlice.row.end), 563 rcSlice.row.step); 564 nl = jStat.arange(rcSlice.col.start, 565 Math.min(A[0].length, rcSlice.col.end), 566 rcSlice.col.step); 567 ml.forEach(function(m, i) { 568 nl.forEach(function(n, j) { 569 A[m][n] = B[i][j]; 570 }); 571 }); 572 return A; 573 }; 574 575 576 // [1,2,3] -> 577 // [[1,0,0],[0,2,0],[0,0,3]] 578 jStat.diagonal = function diagonal(diagArray) { 579 var mat = jStat.zeros(diagArray.length, diagArray.length); 580 diagArray.forEach(function(t, i) { 581 mat[i][i] = t; 582 }); 583 return mat; 584 }; 585 586 587 // return copy of A 588 jStat.copy = function copy(A) { 589 return A.map(function(row) { 590 if (isNumber(row)) 591 return row; 592 return row.map(function(t) { 593 return t; 594 }); 595 }); 596 }; 597 598 599 // TODO: Go over this entire implementation. Seems a tragic waste of resources 600 // doing all this work. Instead, and while ugly, use new Function() to generate 601 // a custom function for each static method. 602 603 // Quick reference. 604 var jProto = jStat.prototype; 605 606 // Default length. 607 jProto.length = 0; 608 609 // For internal use only. 610 // TODO: Check if they're actually used, and if they are then rename them 611 // to _* 612 jProto.push = Array.prototype.push; 613 jProto.sort = Array.prototype.sort; 614 jProto.splice = Array.prototype.splice; 615 jProto.slice = Array.prototype.slice; 616 617 618 // Return a clean array. 619 jProto.toArray = function toArray() { 620 return this.length > 1 ? slice.call(this) : slice.call(this)[0]; 621 }; 622 623 624 // Map a function to a matrix or vector. 625 jProto.map = function map(func, toAlter) { 626 return jStat(jStat.map(this, func, toAlter)); 627 }; 628 629 630 // Cumulatively combine the elements of a matrix or vector using a function. 631 jProto.cumreduce = function cumreduce(func, toAlter) { 632 return jStat(jStat.cumreduce(this, func, toAlter)); 633 }; 634 635 636 // Destructively alter an array. 637 jProto.alter = function alter(func) { 638 jStat.alter(this, func); 639 return this; 640 }; 641 642 643 // Extend prototype with methods that have no argument. 644 (function(funcs) { 645 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 646 jProto[passfunc] = function(func) { 647 var self = this, 648 results; 649 // Check for callback. 650 if (func) { 651 setTimeout(function() { 652 func.call(self, jProto[passfunc].call(self)); 653 }); 654 return this; 655 } 656 results = jStat[passfunc](this); 657 return isArray(results) ? jStat(results) : results; 658 }; 659 })(funcs[i]); 660 })('transpose clear symmetric rows cols dimensions diag antidiag'.split(' ')); 661 662 663 // Extend prototype with methods that have one argument. 664 (function(funcs) { 665 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 666 jProto[passfunc] = function(index, func) { 667 var self = this; 668 // check for callback 669 if (func) { 670 setTimeout(function() { 671 func.call(self, jProto[passfunc].call(self, index)); 672 }); 673 return this; 674 } 675 return jStat(jStat[passfunc](this, index)); 676 }; 677 })(funcs[i]); 678 })('row col'.split(' ')); 679 680 681 // Extend prototype with simple shortcut methods. 682 (function(funcs) { 683 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 684 jProto[passfunc] = function() { 685 return jStat(jStat[passfunc].apply(null, arguments)); 686 }; 687 })(funcs[i]); 688 })('create zeros ones rand identity'.split(' ')); 689 690 691 // Exposing jStat. 692 return jStat; 693 694 }(Math)); 695 (function(jStat, Math) { 696 697 var isFunction = jStat.utils.isFunction; 698 699 // Ascending functions for sort 700 function ascNum(a, b) { return a - b; } 701 702 function clip(arg, min, max) { 703 return Math.max(min, Math.min(arg, max)); 704 } 705 706 707 // sum of an array 708 jStat.sum = function sum(arr) { 709 var sum = 0; 710 var i = arr.length; 711 while (--i >= 0) 712 sum += arr[i]; 713 return sum; 714 }; 715 716 717 // sum squared 718 jStat.sumsqrd = function sumsqrd(arr) { 719 var sum = 0; 720 var i = arr.length; 721 while (--i >= 0) 722 sum += arr[i] * arr[i]; 723 return sum; 724 }; 725 726 727 // sum of squared errors of prediction (SSE) 728 jStat.sumsqerr = function sumsqerr(arr) { 729 var mean = jStat.mean(arr); 730 var sum = 0; 731 var i = arr.length; 732 var tmp; 733 while (--i >= 0) { 734 tmp = arr[i] - mean; 735 sum += tmp * tmp; 736 } 737 return sum; 738 }; 739 740 // sum of an array in each row 741 jStat.sumrow = function sumrow(arr) { 742 var sum = 0; 743 var i = arr.length; 744 while (--i >= 0) 745 sum += arr[i]; 746 return sum; 747 }; 748 749 // product of an array 750 jStat.product = function product(arr) { 751 var prod = 1; 752 var i = arr.length; 753 while (--i >= 0) 754 prod *= arr[i]; 755 return prod; 756 }; 757 758 759 // minimum value of an array 760 jStat.min = function min(arr) { 761 var low = arr[0]; 762 var i = 0; 763 while (++i < arr.length) 764 if (arr[i] < low) 765 low = arr[i]; 766 return low; 767 }; 768 769 770 // maximum value of an array 771 jStat.max = function max(arr) { 772 var high = arr[0]; 773 var i = 0; 774 while (++i < arr.length) 775 if (arr[i] > high) 776 high = arr[i]; 777 return high; 778 }; 779 780 781 // unique values of an array 782 jStat.unique = function unique(arr) { 783 var hash = {}, _arr = []; 784 for(var i = 0; i < arr.length; i++) { 785 if (!hash[arr[i]]) { 786 hash[arr[i]] = true; 787 _arr.push(arr[i]); 788 } 789 } 790 return _arr; 791 }; 792 793 794 // mean value of an array 795 jStat.mean = function mean(arr) { 796 return jStat.sum(arr) / arr.length; 797 }; 798 799 800 // mean squared error (MSE) 801 jStat.meansqerr = function meansqerr(arr) { 802 return jStat.sumsqerr(arr) / arr.length; 803 }; 804 805 806 // geometric mean of an array 807 jStat.geomean = function geomean(arr) { 808 var logs = arr.map(Math.log) 809 var meanOfLogs = jStat.mean(logs) 810 return Math.exp(meanOfLogs) 811 }; 812 813 814 // median of an array 815 jStat.median = function median(arr) { 816 var arrlen = arr.length; 817 var _arr = arr.slice().sort(ascNum); 818 // check if array is even or odd, then return the appropriate 819 return !(arrlen & 1) 820 ? (_arr[(arrlen / 2) - 1 ] + _arr[(arrlen / 2)]) / 2 821 : _arr[(arrlen / 2) | 0 ]; 822 }; 823 824 825 // cumulative sum of an array 826 jStat.cumsum = function cumsum(arr) { 827 return jStat.cumreduce(arr, function (a, b) { return a + b; }); 828 }; 829 830 831 // cumulative product of an array 832 jStat.cumprod = function cumprod(arr) { 833 return jStat.cumreduce(arr, function (a, b) { return a * b; }); 834 }; 835 836 837 // successive differences of a sequence 838 jStat.diff = function diff(arr) { 839 var diffs = []; 840 var arrLen = arr.length; 841 var i; 842 for (i = 1; i < arrLen; i++) 843 diffs.push(arr[i] - arr[i - 1]); 844 return diffs; 845 }; 846 847 848 // ranks of an array 849 jStat.rank = function (arr) { 850 var i; 851 var distinctNumbers = []; 852 var numberCounts = {}; 853 for (i = 0; i < arr.length; i++) { 854 var number = arr[i]; 855 if (numberCounts[number]) { 856 numberCounts[number]++; 857 } else { 858 numberCounts[number] = 1; 859 distinctNumbers.push(number); 860 } 861 } 862 863 var sortedDistinctNumbers = distinctNumbers.sort(ascNum); 864 var numberRanks = {}; 865 var currentRank = 1; 866 for (i = 0; i < sortedDistinctNumbers.length; i++) { 867 var number = sortedDistinctNumbers[i]; 868 var count = numberCounts[number]; 869 var first = currentRank; 870 var last = currentRank + count - 1; 871 var rank = (first + last) / 2; 872 numberRanks[number] = rank; 873 currentRank += count; 874 } 875 876 return arr.map(function (number) { 877 return numberRanks[number]; 878 }); 879 }; 880 881 882 // mode of an array 883 // if there are multiple modes of an array, return all of them 884 // is this the appropriate way of handling it? 885 jStat.mode = function mode(arr) { 886 var arrLen = arr.length; 887 var _arr = arr.slice().sort(ascNum); 888 var count = 1; 889 var maxCount = 0; 890 var numMaxCount = 0; 891 var mode_arr = []; 892 var i; 893 894 for (i = 0; i < arrLen; i++) { 895 if (_arr[i] === _arr[i + 1]) { 896 count++; 897 } else { 898 if (count > maxCount) { 899 mode_arr = [_arr[i]]; 900 maxCount = count; 901 numMaxCount = 0; 902 } 903 // are there multiple max counts 904 else if (count === maxCount) { 905 mode_arr.push(_arr[i]); 906 numMaxCount++; 907 } 908 // resetting count for new value in array 909 count = 1; 910 } 911 } 912 913 return numMaxCount === 0 ? mode_arr[0] : mode_arr; 914 }; 915 916 917 // range of an array 918 jStat.range = function range(arr) { 919 return jStat.max(arr) - jStat.min(arr); 920 }; 921 922 // variance of an array 923 // flag = true indicates sample instead of population 924 jStat.variance = function variance(arr, flag) { 925 return jStat.sumsqerr(arr) / (arr.length - (flag ? 1 : 0)); 926 }; 927 928 // pooled variance of an array of arrays 929 jStat.pooledvariance = function pooledvariance(arr) { 930 var sumsqerr = arr.reduce(function (a, samples) {return a + jStat.sumsqerr(samples);}, 0); 931 var count = arr.reduce(function (a, samples) {return a + samples.length;}, 0); 932 return sumsqerr / (count - arr.length); 933 }; 934 935 // deviation of an array 936 jStat.deviation = function (arr) { 937 var mean = jStat.mean(arr); 938 var arrlen = arr.length; 939 var dev = new Array(arrlen); 940 for (var i = 0; i < arrlen; i++) { 941 dev[i] = arr[i] - mean; 942 } 943 return dev; 944 }; 945 946 // standard deviation of an array 947 // flag = true indicates sample instead of population 948 jStat.stdev = function stdev(arr, flag) { 949 return Math.sqrt(jStat.variance(arr, flag)); 950 }; 951 952 // pooled standard deviation of an array of arrays 953 jStat.pooledstdev = function pooledstdev(arr) { 954 return Math.sqrt(jStat.pooledvariance(arr)); 955 }; 956 957 // mean deviation (mean absolute deviation) of an array 958 jStat.meandev = function meandev(arr) { 959 var mean = jStat.mean(arr); 960 var a = []; 961 for (var i = arr.length - 1; i >= 0; i--) { 962 a.push(Math.abs(arr[i] - mean)); 963 } 964 return jStat.mean(a); 965 }; 966 967 968 // median deviation (median absolute deviation) of an array 969 jStat.meddev = function meddev(arr) { 970 var median = jStat.median(arr); 971 var a = []; 972 for (var i = arr.length - 1; i >= 0; i--) { 973 a.push(Math.abs(arr[i] - median)); 974 } 975 return jStat.median(a); 976 }; 977 978 979 // coefficient of variation 980 jStat.coeffvar = function coeffvar(arr) { 981 return jStat.stdev(arr) / jStat.mean(arr); 982 }; 983 984 985 // quartiles of an array 986 jStat.quartiles = function quartiles(arr) { 987 var arrlen = arr.length; 988 var _arr = arr.slice().sort(ascNum); 989 return [ 990 _arr[ Math.round((arrlen) / 4) - 1 ], 991 _arr[ Math.round((arrlen) / 2) - 1 ], 992 _arr[ Math.round((arrlen) * 3 / 4) - 1 ] 993 ]; 994 }; 995 996 997 // Arbitary quantiles of an array. Direct port of the scipy.stats 998 // implementation by Pierre GF Gerard-Marchant. 999 jStat.quantiles = function quantiles(arr, quantilesArray, alphap, betap) { 1000 var sortedArray = arr.slice().sort(ascNum); 1001 var quantileVals = [quantilesArray.length]; 1002 var n = arr.length; 1003 var i, p, m, aleph, k, gamma; 1004 1005 if (typeof alphap === 'undefined') 1006 alphap = 3 / 8; 1007 if (typeof betap === 'undefined') 1008 betap = 3 / 8; 1009 1010 for (i = 0; i < quantilesArray.length; i++) { 1011 p = quantilesArray[i]; 1012 m = alphap + p * (1 - alphap - betap); 1013 aleph = n * p + m; 1014 k = Math.floor(clip(aleph, 1, n - 1)); 1015 gamma = clip(aleph - k, 0, 1); 1016 quantileVals[i] = (1 - gamma) * sortedArray[k - 1] + gamma * sortedArray[k]; 1017 } 1018 1019 return quantileVals; 1020 }; 1021 1022 // Return the k-th percentile of values in a range, where k is in the range 0..1, inclusive. 1023 // Passing true for the exclusive parameter excludes both endpoints of the range. 1024 jStat.percentile = function percentile(arr, k, exclusive) { 1025 var _arr = arr.slice().sort(ascNum); 1026 var realIndex = k * (_arr.length + (exclusive ? 1 : -1)) + (exclusive ? 0 : 1); 1027 var index = parseInt(realIndex); 1028 var frac = realIndex - index; 1029 if (index + 1 < _arr.length) { 1030 return _arr[index - 1] + frac * (_arr[index] - _arr[index - 1]); 1031 } else { 1032 return _arr[index - 1]; 1033 } 1034 } 1035 1036 // The percentile rank of score in a given array. Returns the percentage 1037 // of all values in the input array that are less than (kind='strict') or 1038 // less or equal than (kind='weak') score. Default is weak. 1039 jStat.percentileOfScore = function percentileOfScore(arr, score, kind) { 1040 var counter = 0; 1041 var len = arr.length; 1042 var strict = false; 1043 var value, i; 1044 1045 if (kind === 'strict') 1046 strict = true; 1047 1048 for (i = 0; i < len; i++) { 1049 value = arr[i]; 1050 if ((strict && value < score) || 1051 (!strict && value <= score)) { 1052 counter++; 1053 } 1054 } 1055 1056 return counter / len; 1057 }; 1058 1059 1060 // Histogram (bin count) data 1061 jStat.histogram = function histogram(arr, binCnt) { 1062 binCnt = binCnt || 4; 1063 var first = jStat.min(arr); 1064 var binWidth = (jStat.max(arr) - first) / binCnt; 1065 var len = arr.length; 1066 var bins = []; 1067 var i; 1068 1069 for (i = 0; i < binCnt; i++) 1070 bins[i] = 0; 1071 for (i = 0; i < len; i++) 1072 bins[Math.min(Math.floor(((arr[i] - first) / binWidth)), binCnt - 1)] += 1; 1073 1074 return bins; 1075 }; 1076 1077 1078 // covariance of two arrays 1079 jStat.covariance = function covariance(arr1, arr2) { 1080 var u = jStat.mean(arr1); 1081 var v = jStat.mean(arr2); 1082 var arr1Len = arr1.length; 1083 var sq_dev = new Array(arr1Len); 1084 var i; 1085 1086 for (i = 0; i < arr1Len; i++) 1087 sq_dev[i] = (arr1[i] - u) * (arr2[i] - v); 1088 1089 return jStat.sum(sq_dev) / (arr1Len - 1); 1090 }; 1091 1092 1093 // (pearson's) population correlation coefficient, rho 1094 jStat.corrcoeff = function corrcoeff(arr1, arr2) { 1095 return jStat.covariance(arr1, arr2) / 1096 jStat.stdev(arr1, 1) / 1097 jStat.stdev(arr2, 1); 1098 }; 1099 1100 // (spearman's) rank correlation coefficient, sp 1101 jStat.spearmancoeff = function (arr1, arr2) { 1102 arr1 = jStat.rank(arr1); 1103 arr2 = jStat.rank(arr2); 1104 //return pearson's correlation of the ranks: 1105 return jStat.corrcoeff(arr1, arr2); 1106 } 1107 1108 1109 // statistical standardized moments (general form of skew/kurt) 1110 jStat.stanMoment = function stanMoment(arr, n) { 1111 var mu = jStat.mean(arr); 1112 var sigma = jStat.stdev(arr); 1113 var len = arr.length; 1114 var skewSum = 0; 1115 1116 for (var i = 0; i < len; i++) 1117 skewSum += Math.pow((arr[i] - mu) / sigma, n); 1118 1119 return skewSum / arr.length; 1120 }; 1121 1122 // (pearson's) moment coefficient of skewness 1123 jStat.skewness = function skewness(arr) { 1124 return jStat.stanMoment(arr, 3); 1125 }; 1126 1127 // (pearson's) (excess) kurtosis 1128 jStat.kurtosis = function kurtosis(arr) { 1129 return jStat.stanMoment(arr, 4) - 3; 1130 }; 1131 1132 1133 var jProto = jStat.prototype; 1134 1135 1136 // Extend jProto with method for calculating cumulative sums and products. 1137 // This differs from the similar extension below as cumsum and cumprod should 1138 // not be run again in the case fullbool === true. 1139 // If a matrix is passed, automatically assume operation should be done on the 1140 // columns. 1141 (function(funcs) { 1142 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 1143 // If a matrix is passed, automatically assume operation should be done on 1144 // the columns. 1145 jProto[passfunc] = function(fullbool, func) { 1146 var arr = []; 1147 var i = 0; 1148 var tmpthis = this; 1149 // Assignment reassignation depending on how parameters were passed in. 1150 if (isFunction(fullbool)) { 1151 func = fullbool; 1152 fullbool = false; 1153 } 1154 // Check if a callback was passed with the function. 1155 if (func) { 1156 setTimeout(function() { 1157 func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool)); 1158 }); 1159 return this; 1160 } 1161 // Check if matrix and run calculations. 1162 if (this.length > 1) { 1163 tmpthis = fullbool === true ? this : this.transpose(); 1164 for (; i < tmpthis.length; i++) 1165 arr[i] = jStat[passfunc](tmpthis[i]); 1166 return arr; 1167 } 1168 // Pass fullbool if only vector, not a matrix. for variance and stdev. 1169 return jStat[passfunc](this[0], fullbool); 1170 }; 1171 })(funcs[i]); 1172 })(('cumsum cumprod').split(' ')); 1173 1174 1175 // Extend jProto with methods which don't require arguments and work on columns. 1176 (function(funcs) { 1177 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 1178 // If a matrix is passed, automatically assume operation should be done on 1179 // the columns. 1180 jProto[passfunc] = function(fullbool, func) { 1181 var arr = []; 1182 var i = 0; 1183 var tmpthis = this; 1184 // Assignment reassignation depending on how parameters were passed in. 1185 if (isFunction(fullbool)) { 1186 func = fullbool; 1187 fullbool = false; 1188 } 1189 // Check if a callback was passed with the function. 1190 if (func) { 1191 setTimeout(function() { 1192 func.call(tmpthis, jProto[passfunc].call(tmpthis, fullbool)); 1193 }); 1194 return this; 1195 } 1196 // Check if matrix and run calculations. 1197 if (this.length > 1) { 1198 if (passfunc !== 'sumrow') 1199 tmpthis = fullbool === true ? this : this.transpose(); 1200 for (; i < tmpthis.length; i++) 1201 arr[i] = jStat[passfunc](tmpthis[i]); 1202 return fullbool === true 1203 ? jStat[passfunc](jStat.utils.toVector(arr)) 1204 : arr; 1205 } 1206 // Pass fullbool if only vector, not a matrix. for variance and stdev. 1207 return jStat[passfunc](this[0], fullbool); 1208 }; 1209 })(funcs[i]); 1210 })(('sum sumsqrd sumsqerr sumrow product min max unique mean meansqerr ' + 1211 'geomean median diff rank mode range variance deviation stdev meandev ' + 1212 'meddev coeffvar quartiles histogram skewness kurtosis').split(' ')); 1213 1214 1215 // Extend jProto with functions that take arguments. Operations on matrices are 1216 // done on columns. 1217 (function(funcs) { 1218 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 1219 jProto[passfunc] = function() { 1220 var arr = []; 1221 var i = 0; 1222 var tmpthis = this; 1223 var args = Array.prototype.slice.call(arguments); 1224 var callbackFunction; 1225 1226 // If the last argument is a function, we assume it's a callback; we 1227 // strip the callback out and call the function again. 1228 if (isFunction(args[args.length - 1])) { 1229 callbackFunction = args[args.length - 1]; 1230 var argsToPass = args.slice(0, args.length - 1); 1231 1232 setTimeout(function() { 1233 callbackFunction.call(tmpthis, 1234 jProto[passfunc].apply(tmpthis, argsToPass)); 1235 }); 1236 return this; 1237 1238 // Otherwise we curry the function args and call normally. 1239 } else { 1240 callbackFunction = undefined; 1241 var curriedFunction = function curriedFunction(vector) { 1242 return jStat[passfunc].apply(tmpthis, [vector].concat(args)); 1243 } 1244 } 1245 1246 // If this is a matrix, run column-by-column. 1247 if (this.length > 1) { 1248 tmpthis = tmpthis.transpose(); 1249 for (; i < tmpthis.length; i++) 1250 arr[i] = curriedFunction(tmpthis[i]); 1251 return arr; 1252 } 1253 1254 // Otherwise run on the vector. 1255 return curriedFunction(this[0]); 1256 }; 1257 })(funcs[i]); 1258 })('quantiles percentileOfScore'.split(' ')); 1259 1260 }(jStat, Math)); 1261 // Special functions // 1262 (function(jStat, Math) { 1263 1264 // Log-gamma function 1265 jStat.gammaln = function gammaln(x) { 1266 var j = 0; 1267 var cof = [ 1268 76.18009172947146, -86.50532032941677, 24.01409824083091, 1269 -1.231739572450155, 0.1208650973866179e-2, -0.5395239384953e-5 1270 ]; 1271 var ser = 1.000000000190015; 1272 var xx, y, tmp; 1273 tmp = (y = xx = x) + 5.5; 1274 tmp -= (xx + 0.5) * Math.log(tmp); 1275 for (; j < 6; j++) 1276 ser += cof[j] / ++y; 1277 return Math.log(2.5066282746310005 * ser / xx) - tmp; 1278 }; 1279 1280 /* 1281 * log-gamma function to support poisson distribution sampling. The 1282 * algorithm comes from SPECFUN by Shanjie Zhang and Jianming Jin and their 1283 * book "Computation of Special Functions", 1996, John Wiley & Sons, Inc. 1284 */ 1285 jStat.loggam = function loggam(x) { 1286 var x0, x2, xp, gl, gl0; 1287 var k, n; 1288 1289 var a = [8.333333333333333e-02, -2.777777777777778e-03, 1290 7.936507936507937e-04, -5.952380952380952e-04, 1291 8.417508417508418e-04, -1.917526917526918e-03, 1292 6.410256410256410e-03, -2.955065359477124e-02, 1293 1.796443723688307e-01, -1.39243221690590e+00]; 1294 x0 = x; 1295 n = 0; 1296 if ((x == 1.0) || (x == 2.0)) { 1297 return 0.0; 1298 } 1299 if (x <= 7.0) { 1300 n = Math.floor(7 - x); 1301 x0 = x + n; 1302 } 1303 x2 = 1.0 / (x0 * x0); 1304 xp = 2 * Math.PI; 1305 gl0 = a[9]; 1306 for (k = 8; k >= 0; k--) { 1307 gl0 *= x2; 1308 gl0 += a[k]; 1309 } 1310 gl = gl0 / x0 + 0.5 * Math.log(xp) + (x0 - 0.5) * Math.log(x0) - x0; 1311 if (x <= 7.0) { 1312 for (k = 1; k <= n; k++) { 1313 gl -= Math.log(x0 - 1.0); 1314 x0 -= 1.0; 1315 } 1316 } 1317 return gl; 1318 } 1319 1320 // gamma of x 1321 jStat.gammafn = function gammafn(x) { 1322 var p = [-1.716185138865495, 24.76565080557592, -379.80425647094563, 1323 629.3311553128184, 866.9662027904133, -31451.272968848367, 1324 -36144.413418691176, 66456.14382024054 1325 ]; 1326 var q = [-30.8402300119739, 315.35062697960416, -1015.1563674902192, 1327 -3107.771671572311, 22538.118420980151, 4755.8462775278811, 1328 -134659.9598649693, -115132.2596755535]; 1329 var fact = false; 1330 var n = 0; 1331 var xden = 0; 1332 var xnum = 0; 1333 var y = x; 1334 var i, z, yi, res; 1335 if (x > 171.6243769536076) { 1336 return Infinity; 1337 } 1338 if (y <= 0) { 1339 res = y % 1 + 3.6e-16; 1340 if (res) { 1341 fact = (!(y & 1) ? 1 : -1) * Math.PI / Math.sin(Math.PI * res); 1342 y = 1 - y; 1343 } else { 1344 return Infinity; 1345 } 1346 } 1347 yi = y; 1348 if (y < 1) { 1349 z = y++; 1350 } else { 1351 z = (y -= n = (y | 0) - 1) - 1; 1352 } 1353 for (i = 0; i < 8; ++i) { 1354 xnum = (xnum + p[i]) * z; 1355 xden = xden * z + q[i]; 1356 } 1357 res = xnum / xden + 1; 1358 if (yi < y) { 1359 res /= yi; 1360 } else if (yi > y) { 1361 for (i = 0; i < n; ++i) { 1362 res *= y; 1363 y++; 1364 } 1365 } 1366 if (fact) { 1367 res = fact / res; 1368 } 1369 return res; 1370 }; 1371 1372 1373 // lower incomplete gamma function, which is usually typeset with a 1374 // lower-case greek gamma as the function symbol 1375 jStat.gammap = function gammap(a, x) { 1376 return jStat.lowRegGamma(a, x) * jStat.gammafn(a); 1377 }; 1378 1379 1380 // The lower regularized incomplete gamma function, usually written P(a,x) 1381 jStat.lowRegGamma = function lowRegGamma(a, x) { 1382 var aln = jStat.gammaln(a); 1383 var ap = a; 1384 var sum = 1 / a; 1385 var del = sum; 1386 var b = x + 1 - a; 1387 var c = 1 / 1.0e-30; 1388 var d = 1 / b; 1389 var h = d; 1390 var i = 1; 1391 // calculate maximum number of itterations required for a 1392 var ITMAX = -~(Math.log((a >= 1) ? a : 1 / a) * 8.5 + a * 0.4 + 17); 1393 var an; 1394 1395 if (x < 0 || a <= 0) { 1396 return NaN; 1397 } else if (x < a + 1) { 1398 for (; i <= ITMAX; i++) { 1399 sum += del *= x / ++ap; 1400 } 1401 return (sum * Math.exp(-x + a * Math.log(x) - (aln))); 1402 } 1403 1404 for (; i <= ITMAX; i++) { 1405 an = -i * (i - a); 1406 b += 2; 1407 d = an * d + b; 1408 c = b + an / c; 1409 d = 1 / d; 1410 h *= d * c; 1411 } 1412 1413 return (1 - h * Math.exp(-x + a * Math.log(x) - (aln))); 1414 }; 1415 1416 // natural log factorial of n 1417 jStat.factorialln = function factorialln(n) { 1418 return n < 0 ? NaN : jStat.gammaln(n + 1); 1419 }; 1420 1421 // factorial of n 1422 jStat.factorial = function factorial(n) { 1423 return n < 0 ? NaN : jStat.gammafn(n + 1); 1424 }; 1425 1426 // combinations of n, m 1427 jStat.combination = function combination(n, m) { 1428 // make sure n or m don't exceed the upper limit of usable values 1429 return (n > 170 || m > 170) 1430 ? Math.exp(jStat.combinationln(n, m)) 1431 : (jStat.factorial(n) / jStat.factorial(m)) / jStat.factorial(n - m); 1432 }; 1433 1434 1435 jStat.combinationln = function combinationln(n, m){ 1436 return jStat.factorialln(n) - jStat.factorialln(m) - jStat.factorialln(n - m); 1437 }; 1438 1439 1440 // permutations of n, m 1441 jStat.permutation = function permutation(n, m) { 1442 return jStat.factorial(n) / jStat.factorial(n - m); 1443 }; 1444 1445 1446 // beta function 1447 jStat.betafn = function betafn(x, y) { 1448 // ensure arguments are positive 1449 if (x <= 0 || y <= 0) 1450 return undefined; 1451 // make sure x + y doesn't exceed the upper limit of usable values 1452 return (x + y > 170) 1453 ? Math.exp(jStat.betaln(x, y)) 1454 : jStat.gammafn(x) * jStat.gammafn(y) / jStat.gammafn(x + y); 1455 }; 1456 1457 1458 // natural logarithm of beta function 1459 jStat.betaln = function betaln(x, y) { 1460 return jStat.gammaln(x) + jStat.gammaln(y) - jStat.gammaln(x + y); 1461 }; 1462 1463 1464 // Evaluates the continued fraction for incomplete beta function by modified 1465 // Lentz's method. 1466 jStat.betacf = function betacf(x, a, b) { 1467 var fpmin = 1e-30; 1468 var m = 1; 1469 var qab = a + b; 1470 var qap = a + 1; 1471 var qam = a - 1; 1472 var c = 1; 1473 var d = 1 - qab * x / qap; 1474 var m2, aa, del, h; 1475 1476 // These q's will be used in factors that occur in the coefficients 1477 if (Math.abs(d) < fpmin) 1478 d = fpmin; 1479 d = 1 / d; 1480 h = d; 1481 1482 for (; m <= 100; m++) { 1483 m2 = 2 * m; 1484 aa = m * (b - m) * x / ((qam + m2) * (a + m2)); 1485 // One step (the even one) of the recurrence 1486 d = 1 + aa * d; 1487 if (Math.abs(d) < fpmin) 1488 d = fpmin; 1489 c = 1 + aa / c; 1490 if (Math.abs(c) < fpmin) 1491 c = fpmin; 1492 d = 1 / d; 1493 h *= d * c; 1494 aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2)); 1495 // Next step of the recurrence (the odd one) 1496 d = 1 + aa * d; 1497 if (Math.abs(d) < fpmin) 1498 d = fpmin; 1499 c = 1 + aa / c; 1500 if (Math.abs(c) < fpmin) 1501 c = fpmin; 1502 d = 1 / d; 1503 del = d * c; 1504 h *= del; 1505 if (Math.abs(del - 1.0) < 3e-7) 1506 break; 1507 } 1508 1509 return h; 1510 }; 1511 1512 1513 // Returns the inverse of the lower regularized inomplete gamma function 1514 jStat.gammapinv = function gammapinv(p, a) { 1515 var j = 0; 1516 var a1 = a - 1; 1517 var EPS = 1e-8; 1518 var gln = jStat.gammaln(a); 1519 var x, err, t, u, pp, lna1, afac; 1520 1521 if (p >= 1) 1522 return Math.max(100, a + 100 * Math.sqrt(a)); 1523 if (p <= 0) 1524 return 0; 1525 if (a > 1) { 1526 lna1 = Math.log(a1); 1527 afac = Math.exp(a1 * (lna1 - 1) - gln); 1528 pp = (p < 0.5) ? p : 1 - p; 1529 t = Math.sqrt(-2 * Math.log(pp)); 1530 x = (2.30753 + t * 0.27061) / (1 + t * (0.99229 + t * 0.04481)) - t; 1531 if (p < 0.5) 1532 x = -x; 1533 x = Math.max(1e-3, 1534 a * Math.pow(1 - 1 / (9 * a) - x / (3 * Math.sqrt(a)), 3)); 1535 } else { 1536 t = 1 - a * (0.253 + a * 0.12); 1537 if (p < t) 1538 x = Math.pow(p / t, 1 / a); 1539 else 1540 x = 1 - Math.log(1 - (p - t) / (1 - t)); 1541 } 1542 1543 for(; j < 12; j++) { 1544 if (x <= 0) 1545 return 0; 1546 err = jStat.lowRegGamma(a, x) - p; 1547 if (a > 1) 1548 t = afac * Math.exp(-(x - a1) + a1 * (Math.log(x) - lna1)); 1549 else 1550 t = Math.exp(-x + a1 * Math.log(x) - gln); 1551 u = err / t; 1552 x -= (t = u / (1 - 0.5 * Math.min(1, u * ((a - 1) / x - 1)))); 1553 if (x <= 0) 1554 x = 0.5 * (x + t); 1555 if (Math.abs(t) < EPS * x) 1556 break; 1557 } 1558 1559 return x; 1560 }; 1561 1562 1563 // Returns the error function erf(x) 1564 jStat.erf = function erf(x) { 1565 var cof = [-1.3026537197817094, 6.4196979235649026e-1, 1.9476473204185836e-2, 1566 -9.561514786808631e-3, -9.46595344482036e-4, 3.66839497852761e-4, 1567 4.2523324806907e-5, -2.0278578112534e-5, -1.624290004647e-6, 1568 1.303655835580e-6, 1.5626441722e-8, -8.5238095915e-8, 1569 6.529054439e-9, 5.059343495e-9, -9.91364156e-10, 1570 -2.27365122e-10, 9.6467911e-11, 2.394038e-12, 1571 -6.886027e-12, 8.94487e-13, 3.13092e-13, 1572 -1.12708e-13, 3.81e-16, 7.106e-15, 1573 -1.523e-15, -9.4e-17, 1.21e-16, 1574 -2.8e-17]; 1575 var j = cof.length - 1; 1576 var isneg = false; 1577 var d = 0; 1578 var dd = 0; 1579 var t, ty, tmp, res; 1580 1581 if (x < 0) { 1582 x = -x; 1583 isneg = true; 1584 } 1585 1586 t = 2 / (2 + x); 1587 ty = 4 * t - 2; 1588 1589 for(; j > 0; j--) { 1590 tmp = d; 1591 d = ty * d - dd + cof[j]; 1592 dd = tmp; 1593 } 1594 1595 res = t * Math.exp(-x * x + 0.5 * (cof[0] + ty * d) - dd); 1596 return isneg ? res - 1 : 1 - res; 1597 }; 1598 1599 1600 // Returns the complmentary error function erfc(x) 1601 jStat.erfc = function erfc(x) { 1602 return 1 - jStat.erf(x); 1603 }; 1604 1605 1606 // Returns the inverse of the complementary error function 1607 jStat.erfcinv = function erfcinv(p) { 1608 var j = 0; 1609 var x, err, t, pp; 1610 if (p >= 2) 1611 return -100; 1612 if (p <= 0) 1613 return 100; 1614 pp = (p < 1) ? p : 2 - p; 1615 t = Math.sqrt(-2 * Math.log(pp / 2)); 1616 x = -0.70711 * ((2.30753 + t * 0.27061) / 1617 (1 + t * (0.99229 + t * 0.04481)) - t); 1618 for (; j < 2; j++) { 1619 err = jStat.erfc(x) - pp; 1620 x += err / (1.12837916709551257 * Math.exp(-x * x) - x * err); 1621 } 1622 return (p < 1) ? x : -x; 1623 }; 1624 1625 1626 // Returns the inverse of the incomplete beta function 1627 jStat.ibetainv = function ibetainv(p, a, b) { 1628 var EPS = 1e-8; 1629 var a1 = a - 1; 1630 var b1 = b - 1; 1631 var j = 0; 1632 var lna, lnb, pp, t, u, err, x, al, h, w, afac; 1633 if (p <= 0) 1634 return 0; 1635 if (p >= 1) 1636 return 1; 1637 if (a >= 1 && b >= 1) { 1638 pp = (p < 0.5) ? p : 1 - p; 1639 t = Math.sqrt(-2 * Math.log(pp)); 1640 x = (2.30753 + t * 0.27061) / (1 + t* (0.99229 + t * 0.04481)) - t; 1641 if (p < 0.5) 1642 x = -x; 1643 al = (x * x - 3) / 6; 1644 h = 2 / (1 / (2 * a - 1) + 1 / (2 * b - 1)); 1645 w = (x * Math.sqrt(al + h) / h) - (1 / (2 * b - 1) - 1 / (2 * a - 1)) * 1646 (al + 5 / 6 - 2 / (3 * h)); 1647 x = a / (a + b * Math.exp(2 * w)); 1648 } else { 1649 lna = Math.log(a / (a + b)); 1650 lnb = Math.log(b / (a + b)); 1651 t = Math.exp(a * lna) / a; 1652 u = Math.exp(b * lnb) / b; 1653 w = t + u; 1654 if (p < t / w) 1655 x = Math.pow(a * w * p, 1 / a); 1656 else 1657 x = 1 - Math.pow(b * w * (1 - p), 1 / b); 1658 } 1659 afac = -jStat.gammaln(a) - jStat.gammaln(b) + jStat.gammaln(a + b); 1660 for(; j < 10; j++) { 1661 if (x === 0 || x === 1) 1662 return x; 1663 err = jStat.ibeta(x, a, b) - p; 1664 t = Math.exp(a1 * Math.log(x) + b1 * Math.log(1 - x) + afac); 1665 u = err / t; 1666 x -= (t = u / (1 - 0.5 * Math.min(1, u * (a1 / x - b1 / (1 - x))))); 1667 if (x <= 0) 1668 x = 0.5 * (x + t); 1669 if (x >= 1) 1670 x = 0.5 * (x + t + 1); 1671 if (Math.abs(t) < EPS * x && j > 0) 1672 break; 1673 } 1674 return x; 1675 }; 1676 1677 1678 // Returns the incomplete beta function I_x(a,b) 1679 jStat.ibeta = function ibeta(x, a, b) { 1680 // Factors in front of the continued fraction. 1681 var bt = (x === 0 || x === 1) ? 0 : 1682 Math.exp(jStat.gammaln(a + b) - jStat.gammaln(a) - 1683 jStat.gammaln(b) + a * Math.log(x) + b * 1684 Math.log(1 - x)); 1685 if (x < 0 || x > 1) 1686 return false; 1687 if (x < (a + 1) / (a + b + 2)) 1688 // Use continued fraction directly. 1689 return bt * jStat.betacf(x, a, b) / a; 1690 // else use continued fraction after making the symmetry transformation. 1691 return 1 - bt * jStat.betacf(1 - x, b, a) / b; 1692 }; 1693 1694 1695 // Returns a normal deviate (mu=0, sigma=1). 1696 // If n and m are specified it returns a object of normal deviates. 1697 jStat.randn = function randn(n, m) { 1698 var u, v, x, y, q; 1699 if (!m) 1700 m = n; 1701 if (n) 1702 return jStat.create(n, m, function() { return jStat.randn(); }); 1703 do { 1704 u = jStat._random_fn(); 1705 v = 1.7156 * (jStat._random_fn() - 0.5); 1706 x = u - 0.449871; 1707 y = Math.abs(v) + 0.386595; 1708 q = x * x + y * (0.19600 * y - 0.25472 * x); 1709 } while (q > 0.27597 && (q > 0.27846 || v * v > -4 * Math.log(u) * u * u)); 1710 return v / u; 1711 }; 1712 1713 1714 // Returns a gamma deviate by the method of Marsaglia and Tsang. 1715 jStat.randg = function randg(shape, n, m) { 1716 var oalph = shape; 1717 var a1, a2, u, v, x, mat; 1718 if (!m) 1719 m = n; 1720 if (!shape) 1721 shape = 1; 1722 if (n) { 1723 mat = jStat.zeros(n,m); 1724 mat.alter(function() { return jStat.randg(shape); }); 1725 return mat; 1726 } 1727 if (shape < 1) 1728 shape += 1; 1729 a1 = shape - 1 / 3; 1730 a2 = 1 / Math.sqrt(9 * a1); 1731 do { 1732 do { 1733 x = jStat.randn(); 1734 v = 1 + a2 * x; 1735 } while(v <= 0); 1736 v = v * v * v; 1737 u = jStat._random_fn(); 1738 } while(u > 1 - 0.331 * Math.pow(x, 4) && 1739 Math.log(u) > 0.5 * x*x + a1 * (1 - v + Math.log(v))); 1740 // alpha > 1 1741 if (shape == oalph) 1742 return a1 * v; 1743 // alpha < 1 1744 do { 1745 u = jStat._random_fn(); 1746 } while(u === 0); 1747 return Math.pow(u, 1 / oalph) * a1 * v; 1748 }; 1749 1750 1751 // making use of static methods on the instance 1752 (function(funcs) { 1753 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 1754 jStat.fn[passfunc] = function() { 1755 return jStat( 1756 jStat.map(this, function(value) { return jStat[passfunc](value); })); 1757 } 1758 })(funcs[i]); 1759 })('gammaln gammafn factorial factorialln'.split(' ')); 1760 1761 1762 (function(funcs) { 1763 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 1764 jStat.fn[passfunc] = function() { 1765 return jStat(jStat[passfunc].apply(null, arguments)); 1766 }; 1767 })(funcs[i]); 1768 })('randn'.split(' ')); 1769 1770 }(jStat, Math)); 1771 (function(jStat, Math) { 1772 1773 // generate all distribution instance methods 1774 (function(list) { 1775 for (var i = 0; i < list.length; i++) (function(func) { 1776 // distribution instance method 1777 jStat[func] = function f(a, b, c) { 1778 if (!(this instanceof f)) 1779 return new f(a, b, c); 1780 this._a = a; 1781 this._b = b; 1782 this._c = c; 1783 return this; 1784 }; 1785 // distribution method to be used on a jStat instance 1786 jStat.fn[func] = function(a, b, c) { 1787 var newthis = jStat[func](a, b, c); 1788 newthis.data = this; 1789 return newthis; 1790 }; 1791 // sample instance method 1792 jStat[func].prototype.sample = function(arr) { 1793 var a = this._a; 1794 var b = this._b; 1795 var c = this._c; 1796 if (arr) 1797 return jStat.alter(arr, function() { 1798 return jStat[func].sample(a, b, c); 1799 }); 1800 else 1801 return jStat[func].sample(a, b, c); 1802 }; 1803 // generate the pdf, cdf and inv instance methods 1804 (function(vals) { 1805 for (var i = 0; i < vals.length; i++) (function(fnfunc) { 1806 jStat[func].prototype[fnfunc] = function(x) { 1807 var a = this._a; 1808 var b = this._b; 1809 var c = this._c; 1810 if (!x && x !== 0) 1811 x = this.data; 1812 if (typeof x !== 'number') { 1813 return jStat.fn.map.call(x, function(x) { 1814 return jStat[func][fnfunc](x, a, b, c); 1815 }); 1816 } 1817 return jStat[func][fnfunc](x, a, b, c); 1818 }; 1819 })(vals[i]); 1820 })('pdf cdf inv'.split(' ')); 1821 // generate the mean, median, mode and variance instance methods 1822 (function(vals) { 1823 for (var i = 0; i < vals.length; i++) (function(fnfunc) { 1824 jStat[func].prototype[fnfunc] = function() { 1825 return jStat[func][fnfunc](this._a, this._b, this._c); 1826 }; 1827 })(vals[i]); 1828 })('mean median mode variance'.split(' ')); 1829 })(list[i]); 1830 })(( 1831 'beta centralF cauchy chisquare exponential gamma invgamma kumaraswamy ' + 1832 'laplace lognormal noncentralt normal pareto studentt weibull uniform ' + 1833 'binomial negbin hypgeom poisson triangular tukey arcsine' 1834 ).split(' ')); 1835 1836 1837 1838 // extend beta function with static methods 1839 jStat.extend(jStat.beta, { 1840 pdf: function pdf(x, alpha, beta) { 1841 // PDF is zero outside the support 1842 if (x > 1 || x < 0) 1843 return 0; 1844 // PDF is one for the uniform case 1845 if (alpha == 1 && beta == 1) 1846 return 1; 1847 1848 if (alpha < 512 && beta < 512) { 1849 return (Math.pow(x, alpha - 1) * Math.pow(1 - x, beta - 1)) / 1850 jStat.betafn(alpha, beta); 1851 } else { 1852 return Math.exp((alpha - 1) * Math.log(x) + 1853 (beta - 1) * Math.log(1 - x) - 1854 jStat.betaln(alpha, beta)); 1855 } 1856 }, 1857 1858 cdf: function cdf(x, alpha, beta) { 1859 return (x > 1 || x < 0) ? (x > 1) * 1 : jStat.ibeta(x, alpha, beta); 1860 }, 1861 1862 inv: function inv(x, alpha, beta) { 1863 return jStat.ibetainv(x, alpha, beta); 1864 }, 1865 1866 mean: function mean(alpha, beta) { 1867 return alpha / (alpha + beta); 1868 }, 1869 1870 median: function median(alpha, beta) { 1871 return jStat.ibetainv(0.5, alpha, beta); 1872 }, 1873 1874 mode: function mode(alpha, beta) { 1875 return (alpha - 1 ) / ( alpha + beta - 2); 1876 }, 1877 1878 // return a random sample 1879 sample: function sample(alpha, beta) { 1880 var u = jStat.randg(alpha); 1881 return u / (u + jStat.randg(beta)); 1882 }, 1883 1884 variance: function variance(alpha, beta) { 1885 return (alpha * beta) / (Math.pow(alpha + beta, 2) * (alpha + beta + 1)); 1886 } 1887 }); 1888 1889 // extend F function with static methods 1890 jStat.extend(jStat.centralF, { 1891 // This implementation of the pdf function avoids float overflow 1892 // See the way that R calculates this value: 1893 // https://svn.r-project.org/R/trunk/src/nmath/df.c 1894 pdf: function pdf(x, df1, df2) { 1895 var p, q, f; 1896 1897 if (x < 0) 1898 return 0; 1899 1900 if (df1 <= 2) { 1901 if (x === 0 && df1 < 2) { 1902 return Infinity; 1903 } 1904 if (x === 0 && df1 === 2) { 1905 return 1; 1906 } 1907 return (1 / jStat.betafn(df1 / 2, df2 / 2)) * 1908 Math.pow(df1 / df2, df1 / 2) * 1909 Math.pow(x, (df1/2) - 1) * 1910 Math.pow((1 + (df1 / df2) * x), -(df1 + df2) / 2); 1911 } 1912 1913 p = (df1 * x) / (df2 + x * df1); 1914 q = df2 / (df2 + x * df1); 1915 f = df1 * q / 2.0; 1916 return f * jStat.binomial.pdf((df1 - 2) / 2, (df1 + df2 - 2) / 2, p); 1917 }, 1918 1919 cdf: function cdf(x, df1, df2) { 1920 if (x < 0) 1921 return 0; 1922 return jStat.ibeta((df1 * x) / (df1 * x + df2), df1 / 2, df2 / 2); 1923 }, 1924 1925 inv: function inv(x, df1, df2) { 1926 return df2 / (df1 * (1 / jStat.ibetainv(x, df1 / 2, df2 / 2) - 1)); 1927 }, 1928 1929 mean: function mean(df1, df2) { 1930 return (df2 > 2) ? df2 / (df2 - 2) : undefined; 1931 }, 1932 1933 mode: function mode(df1, df2) { 1934 return (df1 > 2) ? (df2 * (df1 - 2)) / (df1 * (df2 + 2)) : undefined; 1935 }, 1936 1937 // return a random sample 1938 sample: function sample(df1, df2) { 1939 var x1 = jStat.randg(df1 / 2) * 2; 1940 var x2 = jStat.randg(df2 / 2) * 2; 1941 return (x1 / df1) / (x2 / df2); 1942 }, 1943 1944 variance: function variance(df1, df2) { 1945 if (df2 <= 4) 1946 return undefined; 1947 return 2 * df2 * df2 * (df1 + df2 - 2) / 1948 (df1 * (df2 - 2) * (df2 - 2) * (df2 - 4)); 1949 } 1950 }); 1951 1952 1953 // extend cauchy function with static methods 1954 jStat.extend(jStat.cauchy, { 1955 pdf: function pdf(x, local, scale) { 1956 if (scale < 0) { return 0; } 1957 1958 return (scale / (Math.pow(x - local, 2) + Math.pow(scale, 2))) / Math.PI; 1959 }, 1960 1961 cdf: function cdf(x, local, scale) { 1962 return Math.atan((x - local) / scale) / Math.PI + 0.5; 1963 }, 1964 1965 inv: function(p, local, scale) { 1966 return local + scale * Math.tan(Math.PI * (p - 0.5)); 1967 }, 1968 1969 median: function median(local/*, scale*/) { 1970 return local; 1971 }, 1972 1973 mode: function mode(local/*, scale*/) { 1974 return local; 1975 }, 1976 1977 sample: function sample(local, scale) { 1978 return jStat.randn() * 1979 Math.sqrt(1 / (2 * jStat.randg(0.5))) * scale + local; 1980 } 1981 }); 1982 1983 1984 1985 // extend chisquare function with static methods 1986 jStat.extend(jStat.chisquare, { 1987 pdf: function pdf(x, dof) { 1988 if (x < 0) 1989 return 0; 1990 return (x === 0 && dof === 2) ? 0.5 : 1991 Math.exp((dof / 2 - 1) * Math.log(x) - x / 2 - (dof / 2) * 1992 Math.log(2) - jStat.gammaln(dof / 2)); 1993 }, 1994 1995 cdf: function cdf(x, dof) { 1996 if (x < 0) 1997 return 0; 1998 return jStat.lowRegGamma(dof / 2, x / 2); 1999 }, 2000 2001 inv: function(p, dof) { 2002 return 2 * jStat.gammapinv(p, 0.5 * dof); 2003 }, 2004 2005 mean : function(dof) { 2006 return dof; 2007 }, 2008 2009 // TODO: this is an approximation (is there a better way?) 2010 median: function median(dof) { 2011 return dof * Math.pow(1 - (2 / (9 * dof)), 3); 2012 }, 2013 2014 mode: function mode(dof) { 2015 return (dof - 2 > 0) ? dof - 2 : 0; 2016 }, 2017 2018 sample: function sample(dof) { 2019 return jStat.randg(dof / 2) * 2; 2020 }, 2021 2022 variance: function variance(dof) { 2023 return 2 * dof; 2024 } 2025 }); 2026 2027 2028 2029 // extend exponential function with static methods 2030 jStat.extend(jStat.exponential, { 2031 pdf: function pdf(x, rate) { 2032 return x < 0 ? 0 : rate * Math.exp(-rate * x); 2033 }, 2034 2035 cdf: function cdf(x, rate) { 2036 return x < 0 ? 0 : 1 - Math.exp(-rate * x); 2037 }, 2038 2039 inv: function(p, rate) { 2040 return -Math.log(1 - p) / rate; 2041 }, 2042 2043 mean : function(rate) { 2044 return 1 / rate; 2045 }, 2046 2047 median: function (rate) { 2048 return (1 / rate) * Math.log(2); 2049 }, 2050 2051 mode: function mode(/*rate*/) { 2052 return 0; 2053 }, 2054 2055 sample: function sample(rate) { 2056 return -1 / rate * Math.log(jStat._random_fn()); 2057 }, 2058 2059 variance : function(rate) { 2060 return Math.pow(rate, -2); 2061 } 2062 }); 2063 2064 2065 2066 // extend gamma function with static methods 2067 jStat.extend(jStat.gamma, { 2068 pdf: function pdf(x, shape, scale) { 2069 if (x < 0) 2070 return 0; 2071 return (x === 0 && shape === 1) ? 1 / scale : 2072 Math.exp((shape - 1) * Math.log(x) - x / scale - 2073 jStat.gammaln(shape) - shape * Math.log(scale)); 2074 }, 2075 2076 cdf: function cdf(x, shape, scale) { 2077 if (x < 0) 2078 return 0; 2079 return jStat.lowRegGamma(shape, x / scale); 2080 }, 2081 2082 inv: function(p, shape, scale) { 2083 return jStat.gammapinv(p, shape) * scale; 2084 }, 2085 2086 mean : function(shape, scale) { 2087 return shape * scale; 2088 }, 2089 2090 mode: function mode(shape, scale) { 2091 if(shape > 1) return (shape - 1) * scale; 2092 return undefined; 2093 }, 2094 2095 sample: function sample(shape, scale) { 2096 return jStat.randg(shape) * scale; 2097 }, 2098 2099 variance: function variance(shape, scale) { 2100 return shape * scale * scale; 2101 } 2102 }); 2103 2104 // extend inverse gamma function with static methods 2105 jStat.extend(jStat.invgamma, { 2106 pdf: function pdf(x, shape, scale) { 2107 if (x <= 0) 2108 return 0; 2109 return Math.exp(-(shape + 1) * Math.log(x) - scale / x - 2110 jStat.gammaln(shape) + shape * Math.log(scale)); 2111 }, 2112 2113 cdf: function cdf(x, shape, scale) { 2114 if (x <= 0) 2115 return 0; 2116 return 1 - jStat.lowRegGamma(shape, scale / x); 2117 }, 2118 2119 inv: function(p, shape, scale) { 2120 return scale / jStat.gammapinv(1 - p, shape); 2121 }, 2122 2123 mean : function(shape, scale) { 2124 return (shape > 1) ? scale / (shape - 1) : undefined; 2125 }, 2126 2127 mode: function mode(shape, scale) { 2128 return scale / (shape + 1); 2129 }, 2130 2131 sample: function sample(shape, scale) { 2132 return scale / jStat.randg(shape); 2133 }, 2134 2135 variance: function variance(shape, scale) { 2136 if (shape <= 2) 2137 return undefined; 2138 return scale * scale / ((shape - 1) * (shape - 1) * (shape - 2)); 2139 } 2140 }); 2141 2142 2143 // extend kumaraswamy function with static methods 2144 jStat.extend(jStat.kumaraswamy, { 2145 pdf: function pdf(x, alpha, beta) { 2146 if (x === 0 && alpha === 1) 2147 return beta; 2148 else if (x === 1 && beta === 1) 2149 return alpha; 2150 return Math.exp(Math.log(alpha) + Math.log(beta) + (alpha - 1) * 2151 Math.log(x) + (beta - 1) * 2152 Math.log(1 - Math.pow(x, alpha))); 2153 }, 2154 2155 cdf: function cdf(x, alpha, beta) { 2156 if (x < 0) 2157 return 0; 2158 else if (x > 1) 2159 return 1; 2160 return (1 - Math.pow(1 - Math.pow(x, alpha), beta)); 2161 }, 2162 2163 inv: function inv(p, alpha, beta) { 2164 return Math.pow(1 - Math.pow(1 - p, 1 / beta), 1 / alpha); 2165 }, 2166 2167 mean : function(alpha, beta) { 2168 return (beta * jStat.gammafn(1 + 1 / alpha) * 2169 jStat.gammafn(beta)) / (jStat.gammafn(1 + 1 / alpha + beta)); 2170 }, 2171 2172 median: function median(alpha, beta) { 2173 return Math.pow(1 - Math.pow(2, -1 / beta), 1 / alpha); 2174 }, 2175 2176 mode: function mode(alpha, beta) { 2177 if (!(alpha >= 1 && beta >= 1 && (alpha !== 1 && beta !== 1))) 2178 return undefined; 2179 return Math.pow((alpha - 1) / (alpha * beta - 1), 1 / alpha); 2180 }, 2181 2182 variance: function variance(/*alpha, beta*/) { 2183 throw new Error('variance not yet implemented'); 2184 // TODO: complete this 2185 } 2186 }); 2187 2188 2189 2190 // extend lognormal function with static methods 2191 jStat.extend(jStat.lognormal, { 2192 pdf: function pdf(x, mu, sigma) { 2193 if (x <= 0) 2194 return 0; 2195 return Math.exp(-Math.log(x) - 0.5 * Math.log(2 * Math.PI) - 2196 Math.log(sigma) - Math.pow(Math.log(x) - mu, 2) / 2197 (2 * sigma * sigma)); 2198 }, 2199 2200 cdf: function cdf(x, mu, sigma) { 2201 if (x < 0) 2202 return 0; 2203 return 0.5 + 2204 (0.5 * jStat.erf((Math.log(x) - mu) / Math.sqrt(2 * sigma * sigma))); 2205 }, 2206 2207 inv: function(p, mu, sigma) { 2208 return Math.exp(-1.41421356237309505 * sigma * jStat.erfcinv(2 * p) + mu); 2209 }, 2210 2211 mean: function mean(mu, sigma) { 2212 return Math.exp(mu + sigma * sigma / 2); 2213 }, 2214 2215 median: function median(mu/*, sigma*/) { 2216 return Math.exp(mu); 2217 }, 2218 2219 mode: function mode(mu, sigma) { 2220 return Math.exp(mu - sigma * sigma); 2221 }, 2222 2223 sample: function sample(mu, sigma) { 2224 return Math.exp(jStat.randn() * sigma + mu); 2225 }, 2226 2227 variance: function variance(mu, sigma) { 2228 return (Math.exp(sigma * sigma) - 1) * Math.exp(2 * mu + sigma * sigma); 2229 } 2230 }); 2231 2232 2233 2234 // extend noncentralt function with static methods 2235 jStat.extend(jStat.noncentralt, { 2236 pdf: function pdf(x, dof, ncp) { 2237 var tol = 1e-14; 2238 if (Math.abs(ncp) < tol) // ncp approx 0; use student-t 2239 return jStat.studentt.pdf(x, dof) 2240 2241 if (Math.abs(x) < tol) { // different formula for x == 0 2242 return Math.exp(jStat.gammaln((dof + 1) / 2) - ncp * ncp / 2 - 2243 0.5 * Math.log(Math.PI * dof) - jStat.gammaln(dof / 2)); 2244 } 2245 2246 // formula for x != 0 2247 return dof / x * 2248 (jStat.noncentralt.cdf(x * Math.sqrt(1 + 2 / dof), dof+2, ncp) - 2249 jStat.noncentralt.cdf(x, dof, ncp)); 2250 }, 2251 2252 cdf: function cdf(x, dof, ncp) { 2253 var tol = 1e-14; 2254 var min_iterations = 200; 2255 2256 if (Math.abs(ncp) < tol) // ncp approx 0; use student-t 2257 return jStat.studentt.cdf(x, dof); 2258 2259 // turn negative x into positive and flip result afterwards 2260 var flip = false; 2261 if (x < 0) { 2262 flip = true; 2263 ncp = -ncp; 2264 } 2265 2266 var prob = jStat.normal.cdf(-ncp, 0, 1); 2267 var value = tol + 1; 2268 // use value at last two steps to determine convergence 2269 var lastvalue = value; 2270 var y = x * x / (x * x + dof); 2271 var j = 0; 2272 var p = Math.exp(-ncp * ncp / 2); 2273 var q = Math.exp(-ncp * ncp / 2 - 0.5 * Math.log(2) - 2274 jStat.gammaln(3 / 2)) * ncp; 2275 while (j < min_iterations || lastvalue > tol || value > tol) { 2276 lastvalue = value; 2277 if (j > 0) { 2278 p *= (ncp * ncp) / (2 * j); 2279 q *= (ncp * ncp) / (2 * (j + 1 / 2)); 2280 } 2281 value = p * jStat.beta.cdf(y, j + 0.5, dof / 2) + 2282 q * jStat.beta.cdf(y, j+1, dof/2); 2283 prob += 0.5 * value; 2284 j++; 2285 } 2286 2287 return flip ? (1 - prob) : prob; 2288 } 2289 }); 2290 2291 2292 // extend normal function with static methods 2293 jStat.extend(jStat.normal, { 2294 pdf: function pdf(x, mean, std) { 2295 return Math.exp(-0.5 * Math.log(2 * Math.PI) - 2296 Math.log(std) - Math.pow(x - mean, 2) / (2 * std * std)); 2297 }, 2298 2299 cdf: function cdf(x, mean, std) { 2300 return 0.5 * (1 + jStat.erf((x - mean) / Math.sqrt(2 * std * std))); 2301 }, 2302 2303 inv: function(p, mean, std) { 2304 return -1.41421356237309505 * std * jStat.erfcinv(2 * p) + mean; 2305 }, 2306 2307 mean : function(mean/*, std*/) { 2308 return mean; 2309 }, 2310 2311 median: function median(mean/*, std*/) { 2312 return mean; 2313 }, 2314 2315 mode: function (mean/*, std*/) { 2316 return mean; 2317 }, 2318 2319 sample: function sample(mean, std) { 2320 return jStat.randn() * std + mean; 2321 }, 2322 2323 variance : function(mean, std) { 2324 return std * std; 2325 } 2326 }); 2327 2328 2329 2330 // extend pareto function with static methods 2331 jStat.extend(jStat.pareto, { 2332 pdf: function pdf(x, scale, shape) { 2333 if (x < scale) 2334 return 0; 2335 return (shape * Math.pow(scale, shape)) / Math.pow(x, shape + 1); 2336 }, 2337 2338 cdf: function cdf(x, scale, shape) { 2339 if (x < scale) 2340 return 0; 2341 return 1 - Math.pow(scale / x, shape); 2342 }, 2343 2344 inv: function inv(p, scale, shape) { 2345 return scale / Math.pow(1 - p, 1 / shape); 2346 }, 2347 2348 mean: function mean(scale, shape) { 2349 if (shape <= 1) 2350 return undefined; 2351 return (shape * Math.pow(scale, shape)) / (shape - 1); 2352 }, 2353 2354 median: function median(scale, shape) { 2355 return scale * (shape * Math.SQRT2); 2356 }, 2357 2358 mode: function mode(scale/*, shape*/) { 2359 return scale; 2360 }, 2361 2362 variance : function(scale, shape) { 2363 if (shape <= 2) 2364 return undefined; 2365 return (scale*scale * shape) / (Math.pow(shape - 1, 2) * (shape - 2)); 2366 } 2367 }); 2368 2369 2370 2371 // extend studentt function with static methods 2372 jStat.extend(jStat.studentt, { 2373 pdf: function pdf(x, dof) { 2374 dof = dof > 1e100 ? 1e100 : dof; 2375 return (1/(Math.sqrt(dof) * jStat.betafn(0.5, dof/2))) * 2376 Math.pow(1 + ((x * x) / dof), -((dof + 1) / 2)); 2377 }, 2378 2379 cdf: function cdf(x, dof) { 2380 var dof2 = dof / 2; 2381 return jStat.ibeta((x + Math.sqrt(x * x + dof)) / 2382 (2 * Math.sqrt(x * x + dof)), dof2, dof2); 2383 }, 2384 2385 inv: function(p, dof) { 2386 var x = jStat.ibetainv(2 * Math.min(p, 1 - p), 0.5 * dof, 0.5); 2387 x = Math.sqrt(dof * (1 - x) / x); 2388 return (p > 0.5) ? x : -x; 2389 }, 2390 2391 mean: function mean(dof) { 2392 return (dof > 1) ? 0 : undefined; 2393 }, 2394 2395 median: function median(/*dof*/) { 2396 return 0; 2397 }, 2398 2399 mode: function mode(/*dof*/) { 2400 return 0; 2401 }, 2402 2403 sample: function sample(dof) { 2404 return jStat.randn() * Math.sqrt(dof / (2 * jStat.randg(dof / 2))); 2405 }, 2406 2407 variance: function variance(dof) { 2408 return (dof > 2) ? dof / (dof - 2) : (dof > 1) ? Infinity : undefined; 2409 } 2410 }); 2411 2412 2413 2414 // extend weibull function with static methods 2415 jStat.extend(jStat.weibull, { 2416 pdf: function pdf(x, scale, shape) { 2417 if (x < 0 || scale < 0 || shape < 0) 2418 return 0; 2419 return (shape / scale) * Math.pow((x / scale), (shape - 1)) * 2420 Math.exp(-(Math.pow((x / scale), shape))); 2421 }, 2422 2423 cdf: function cdf(x, scale, shape) { 2424 return x < 0 ? 0 : 1 - Math.exp(-Math.pow((x / scale), shape)); 2425 }, 2426 2427 inv: function(p, scale, shape) { 2428 return scale * Math.pow(-Math.log(1 - p), 1 / shape); 2429 }, 2430 2431 mean : function(scale, shape) { 2432 return scale * jStat.gammafn(1 + 1 / shape); 2433 }, 2434 2435 median: function median(scale, shape) { 2436 return scale * Math.pow(Math.log(2), 1 / shape); 2437 }, 2438 2439 mode: function mode(scale, shape) { 2440 if (shape <= 1) 2441 return 0; 2442 return scale * Math.pow((shape - 1) / shape, 1 / shape); 2443 }, 2444 2445 sample: function sample(scale, shape) { 2446 return scale * Math.pow(-Math.log(jStat._random_fn()), 1 / shape); 2447 }, 2448 2449 variance: function variance(scale, shape) { 2450 return scale * scale * jStat.gammafn(1 + 2 / shape) - 2451 Math.pow(jStat.weibull.mean(scale, shape), 2); 2452 } 2453 }); 2454 2455 2456 2457 // extend uniform function with static methods 2458 jStat.extend(jStat.uniform, { 2459 pdf: function pdf(x, a, b) { 2460 return (x < a || x > b) ? 0 : 1 / (b - a); 2461 }, 2462 2463 cdf: function cdf(x, a, b) { 2464 if (x < a) 2465 return 0; 2466 else if (x < b) 2467 return (x - a) / (b - a); 2468 return 1; 2469 }, 2470 2471 inv: function(p, a, b) { 2472 return a + (p * (b - a)); 2473 }, 2474 2475 mean: function mean(a, b) { 2476 return 0.5 * (a + b); 2477 }, 2478 2479 median: function median(a, b) { 2480 return jStat.mean(a, b); 2481 }, 2482 2483 mode: function mode(/*a, b*/) { 2484 throw new Error('mode is not yet implemented'); 2485 }, 2486 2487 sample: function sample(a, b) { 2488 return (a / 2 + b / 2) + (b / 2 - a / 2) * (2 * jStat._random_fn() - 1); 2489 }, 2490 2491 variance: function variance(a, b) { 2492 return Math.pow(b - a, 2) / 12; 2493 } 2494 }); 2495 2496 2497 // Got this from http://www.math.ucla.edu/~tom/distributions/binomial.html 2498 function betinc(x, a, b, eps) { 2499 var a0 = 0; 2500 var b0 = 1; 2501 var a1 = 1; 2502 var b1 = 1; 2503 var m9 = 0; 2504 var a2 = 0; 2505 var c9; 2506 2507 while (Math.abs((a1 - a2) / a1) > eps) { 2508 a2 = a1; 2509 c9 = -(a + m9) * (a + b + m9) * x / (a + 2 * m9) / (a + 2 * m9 + 1); 2510 a0 = a1 + c9 * a0; 2511 b0 = b1 + c9 * b0; 2512 m9 = m9 + 1; 2513 c9 = m9 * (b - m9) * x / (a + 2 * m9 - 1) / (a + 2 * m9); 2514 a1 = a0 + c9 * a1; 2515 b1 = b0 + c9 * b1; 2516 a0 = a0 / b1; 2517 b0 = b0 / b1; 2518 a1 = a1 / b1; 2519 b1 = 1; 2520 } 2521 2522 return a1 / a; 2523 } 2524 2525 2526 // extend uniform function with static methods 2527 jStat.extend(jStat.binomial, { 2528 pdf: function pdf(k, n, p) { 2529 return (p === 0 || p === 1) ? 2530 ((n * p) === k ? 1 : 0) : 2531 jStat.combination(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k); 2532 }, 2533 2534 cdf: function cdf(x, n, p) { 2535 var betacdf; 2536 var eps = 1e-10; 2537 2538 if (x < 0) 2539 return 0; 2540 if (x >= n) 2541 return 1; 2542 if (p < 0 || p > 1 || n <= 0) 2543 return NaN; 2544 2545 x = Math.floor(x); 2546 var z = p; 2547 var a = x + 1; 2548 var b = n - x; 2549 var s = a + b; 2550 var bt = Math.exp(jStat.gammaln(s) - jStat.gammaln(b) - 2551 jStat.gammaln(a) + a * Math.log(z) + b * Math.log(1 - z)); 2552 2553 if (z < (a + 1) / (s + 2)) 2554 betacdf = bt * betinc(z, a, b, eps); 2555 else 2556 betacdf = 1 - bt * betinc(1 - z, b, a, eps); 2557 2558 return Math.round((1 - betacdf) * (1 / eps)) / (1 / eps); 2559 } 2560 }); 2561 2562 2563 2564 // extend uniform function with static methods 2565 jStat.extend(jStat.negbin, { 2566 pdf: function pdf(k, r, p) { 2567 if (k !== k >>> 0) 2568 return false; 2569 if (k < 0) 2570 return 0; 2571 return jStat.combination(k + r - 1, r - 1) * 2572 Math.pow(1 - p, k) * Math.pow(p, r); 2573 }, 2574 2575 cdf: function cdf(x, r, p) { 2576 var sum = 0, 2577 k = 0; 2578 if (x < 0) return 0; 2579 for (; k <= x; k++) { 2580 sum += jStat.negbin.pdf(k, r, p); 2581 } 2582 return sum; 2583 } 2584 }); 2585 2586 2587 2588 // extend uniform function with static methods 2589 jStat.extend(jStat.hypgeom, { 2590 pdf: function pdf(k, N, m, n) { 2591 // Hypergeometric PDF. 2592 2593 // A simplification of the CDF algorithm below. 2594 2595 // k = number of successes drawn 2596 // N = population size 2597 // m = number of successes in population 2598 // n = number of items drawn from population 2599 2600 if(k !== k | 0) { 2601 return false; 2602 } else if(k < 0 || k < m - (N - n)) { 2603 // It's impossible to have this few successes drawn. 2604 return 0; 2605 } else if(k > n || k > m) { 2606 // It's impossible to have this many successes drawn. 2607 return 0; 2608 } else if (m * 2 > N) { 2609 // More than half the population is successes. 2610 2611 if(n * 2 > N) { 2612 // More than half the population is sampled. 2613 2614 return jStat.hypgeom.pdf(N - m - n + k, N, N - m, N - n) 2615 } else { 2616 // Half or less of the population is sampled. 2617 2618 return jStat.hypgeom.pdf(n - k, N, N - m, n); 2619 } 2620 2621 } else if(n * 2 > N) { 2622 // Half or less is successes. 2623 2624 return jStat.hypgeom.pdf(m - k, N, m, N - n); 2625 2626 } else if(m < n) { 2627 // We want to have the number of things sampled to be less than the 2628 // successes available. So swap the definitions of successful and sampled. 2629 return jStat.hypgeom.pdf(k, N, n, m); 2630 } else { 2631 // If we get here, half or less of the population was sampled, half or 2632 // less of it was successes, and we had fewer sampled things than 2633 // successes. Now we can do this complicated iterative algorithm in an 2634 // efficient way. 2635 2636 // The basic premise of the algorithm is that we partially normalize our 2637 // intermediate product to keep it in a numerically good region, and then 2638 // finish the normalization at the end. 2639 2640 // This variable holds the scaled probability of the current number of 2641 // successes. 2642 var scaledPDF = 1; 2643 2644 // This keeps track of how much we have normalized. 2645 var samplesDone = 0; 2646 2647 for(var i = 0; i < k; i++) { 2648 // For every possible number of successes up to that observed... 2649 2650 while(scaledPDF > 1 && samplesDone < n) { 2651 // Intermediate result is growing too big. Apply some of the 2652 // normalization to shrink everything. 2653 2654 scaledPDF *= 1 - (m / (N - samplesDone)); 2655 2656 // Say we've normalized by this sample already. 2657 samplesDone++; 2658 } 2659 2660 // Work out the partially-normalized hypergeometric PDF for the next 2661 // number of successes 2662 scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1)); 2663 } 2664 2665 for(; samplesDone < n; samplesDone++) { 2666 // Apply all the rest of the normalization 2667 scaledPDF *= 1 - (m / (N - samplesDone)); 2668 } 2669 2670 // Bound answer sanely before returning. 2671 return Math.min(1, Math.max(0, scaledPDF)); 2672 } 2673 }, 2674 2675 cdf: function cdf(x, N, m, n) { 2676 // Hypergeometric CDF. 2677 2678 // This algorithm is due to Prof. Thomas S. Ferguson, <tom@math.ucla.edu>, 2679 // and comes from his hypergeometric test calculator at 2680 // <http://www.math.ucla.edu/~tom/distributions/Hypergeometric.html>. 2681 2682 // x = number of successes drawn 2683 // N = population size 2684 // m = number of successes in population 2685 // n = number of items drawn from population 2686 2687 if(x < 0 || x < m - (N - n)) { 2688 // It's impossible to have this few successes drawn or fewer. 2689 return 0; 2690 } else if(x >= n || x >= m) { 2691 // We will always have this many successes or fewer. 2692 return 1; 2693 } else if (m * 2 > N) { 2694 // More than half the population is successes. 2695 2696 if(n * 2 > N) { 2697 // More than half the population is sampled. 2698 2699 return jStat.hypgeom.cdf(N - m - n + x, N, N - m, N - n) 2700 } else { 2701 // Half or less of the population is sampled. 2702 2703 return 1 - jStat.hypgeom.cdf(n - x - 1, N, N - m, n); 2704 } 2705 2706 } else if(n * 2 > N) { 2707 // Half or less is successes. 2708 2709 return 1 - jStat.hypgeom.cdf(m - x - 1, N, m, N - n); 2710 2711 } else if(m < n) { 2712 // We want to have the number of things sampled to be less than the 2713 // successes available. So swap the definitions of successful and sampled. 2714 return jStat.hypgeom.cdf(x, N, n, m); 2715 } else { 2716 // If we get here, half or less of the population was sampled, half or 2717 // less of it was successes, and we had fewer sampled things than 2718 // successes. Now we can do this complicated iterative algorithm in an 2719 // efficient way. 2720 2721 // The basic premise of the algorithm is that we partially normalize our 2722 // intermediate sum to keep it in a numerically good region, and then 2723 // finish the normalization at the end. 2724 2725 // Holds the intermediate, scaled total CDF. 2726 var scaledCDF = 1; 2727 2728 // This variable holds the scaled probability of the current number of 2729 // successes. 2730 var scaledPDF = 1; 2731 2732 // This keeps track of how much we have normalized. 2733 var samplesDone = 0; 2734 2735 for(var i = 0; i < x; i++) { 2736 // For every possible number of successes up to that observed... 2737 2738 while(scaledCDF > 1 && samplesDone < n) { 2739 // Intermediate result is growing too big. Apply some of the 2740 // normalization to shrink everything. 2741 2742 var factor = 1 - (m / (N - samplesDone)); 2743 2744 scaledPDF *= factor; 2745 scaledCDF *= factor; 2746 2747 // Say we've normalized by this sample already. 2748 samplesDone++; 2749 } 2750 2751 // Work out the partially-normalized hypergeometric PDF for the next 2752 // number of successes 2753 scaledPDF *= (n - i) * (m - i) / ((i + 1) * (N - m - n + i + 1)); 2754 2755 // Add to the CDF answer. 2756 scaledCDF += scaledPDF; 2757 } 2758 2759 for(; samplesDone < n; samplesDone++) { 2760 // Apply all the rest of the normalization 2761 scaledCDF *= 1 - (m / (N - samplesDone)); 2762 } 2763 2764 // Bound answer sanely before returning. 2765 return Math.min(1, Math.max(0, scaledCDF)); 2766 } 2767 } 2768 }); 2769 2770 2771 2772 // extend uniform function with static methods 2773 jStat.extend(jStat.poisson, { 2774 pdf: function pdf(k, l) { 2775 if (l < 0 || (k % 1) !== 0 || k < 0) { 2776 return 0; 2777 } 2778 2779 return Math.pow(l, k) * Math.exp(-l) / jStat.factorial(k); 2780 }, 2781 2782 cdf: function cdf(x, l) { 2783 var sumarr = [], 2784 k = 0; 2785 if (x < 0) return 0; 2786 for (; k <= x; k++) { 2787 sumarr.push(jStat.poisson.pdf(k, l)); 2788 } 2789 return jStat.sum(sumarr); 2790 }, 2791 2792 mean : function(l) { 2793 return l; 2794 }, 2795 2796 variance : function(l) { 2797 return l; 2798 }, 2799 2800 sampleSmall: function sampleSmall(l) { 2801 var p = 1, k = 0, L = Math.exp(-l); 2802 do { 2803 k++; 2804 p *= jStat._random_fn(); 2805 } while (p > L); 2806 return k - 1; 2807 }, 2808 2809 sampleLarge: function sampleLarge(l) { 2810 var lam = l; 2811 var k; 2812 var U, V, slam, loglam, a, b, invalpha, vr, us; 2813 2814 slam = Math.sqrt(lam); 2815 loglam = Math.log(lam); 2816 b = 0.931 + 2.53 * slam; 2817 a = -0.059 + 0.02483 * b; 2818 invalpha = 1.1239 + 1.1328 / (b - 3.4); 2819 vr = 0.9277 - 3.6224 / (b - 2); 2820 2821 while (1) { 2822 U = Math.random() - 0.5; 2823 V = Math.random(); 2824 us = 0.5 - Math.abs(U); 2825 k = Math.floor((2 * a / us + b) * U + lam + 0.43); 2826 if ((us >= 0.07) && (V <= vr)) { 2827 return k; 2828 } 2829 if ((k < 0) || ((us < 0.013) && (V > us))) { 2830 continue; 2831 } 2832 /* log(V) == log(0.0) ok here */ 2833 /* if U==0.0 so that us==0.0, log is ok since always returns */ 2834 if ((Math.log(V) + Math.log(invalpha) - Math.log(a / (us * us) + b)) <= (-lam + k * loglam - jStat.loggam(k + 1))) { 2835 return k; 2836 } 2837 } 2838 }, 2839 2840 sample: function sample(l) { 2841 if (l < 10) 2842 return this.sampleSmall(l); 2843 else 2844 return this.sampleLarge(l); 2845 } 2846 }); 2847 2848 // extend triangular function with static methods 2849 jStat.extend(jStat.triangular, { 2850 pdf: function pdf(x, a, b, c) { 2851 if (b <= a || c < a || c > b) { 2852 return NaN; 2853 } else { 2854 if (x < a || x > b) { 2855 return 0; 2856 } else if (x < c) { 2857 return (2 * (x - a)) / ((b - a) * (c - a)); 2858 } else if (x === c) { 2859 return (2 / (b - a)); 2860 } else { // x > c 2861 return (2 * (b - x)) / ((b - a) * (b - c)); 2862 } 2863 } 2864 }, 2865 2866 cdf: function cdf(x, a, b, c) { 2867 if (b <= a || c < a || c > b) 2868 return NaN; 2869 if (x <= a) 2870 return 0; 2871 else if (x >= b) 2872 return 1; 2873 if (x <= c) 2874 return Math.pow(x - a, 2) / ((b - a) * (c - a)); 2875 else // x > c 2876 return 1 - Math.pow(b - x, 2) / ((b - a) * (b - c)); 2877 }, 2878 2879 inv: function inv(p, a, b, c) { 2880 if (b <= a || c < a || c > b) { 2881 return NaN; 2882 } else { 2883 if (p <= ((c - a) / (b - a))) { 2884 return a + (b - a) * Math.sqrt(p * ((c - a) / (b - a))); 2885 } else { // p > ((c - a) / (b - a)) 2886 return a + (b - a) * (1 - Math.sqrt((1 - p) * (1 - ((c - a) / (b - a))))); 2887 } 2888 } 2889 }, 2890 2891 mean: function mean(a, b, c) { 2892 return (a + b + c) / 3; 2893 }, 2894 2895 median: function median(a, b, c) { 2896 if (c <= (a + b) / 2) { 2897 return b - Math.sqrt((b - a) * (b - c)) / Math.sqrt(2); 2898 } else if (c > (a + b) / 2) { 2899 return a + Math.sqrt((b - a) * (c - a)) / Math.sqrt(2); 2900 } 2901 }, 2902 2903 mode: function mode(a, b, c) { 2904 return c; 2905 }, 2906 2907 sample: function sample(a, b, c) { 2908 var u = jStat._random_fn(); 2909 if (u < ((c - a) / (b - a))) 2910 return a + Math.sqrt(u * (b - a) * (c - a)) 2911 return b - Math.sqrt((1 - u) * (b - a) * (b - c)); 2912 }, 2913 2914 variance: function variance(a, b, c) { 2915 return (a * a + b * b + c * c - a * b - a * c - b * c) / 18; 2916 } 2917 }); 2918 2919 2920 // extend arcsine function with static methods 2921 jStat.extend(jStat.arcsine, { 2922 pdf: function pdf(x, a, b) { 2923 if (b <= a) return NaN; 2924 2925 return (x <= a || x >= b) ? 0 : 2926 (2 / Math.PI) * 2927 Math.pow(Math.pow(b - a, 2) - 2928 Math.pow(2 * x - a - b, 2), -0.5); 2929 }, 2930 2931 cdf: function cdf(x, a, b) { 2932 if (x < a) 2933 return 0; 2934 else if (x < b) 2935 return (2 / Math.PI) * Math.asin(Math.sqrt((x - a)/(b - a))); 2936 return 1; 2937 }, 2938 2939 inv: function(p, a, b) { 2940 return a + (0.5 - 0.5 * Math.cos(Math.PI * p)) * (b - a); 2941 }, 2942 2943 mean: function mean(a, b) { 2944 if (b <= a) return NaN; 2945 return (a + b) / 2; 2946 }, 2947 2948 median: function median(a, b) { 2949 if (b <= a) return NaN; 2950 return (a + b) / 2; 2951 }, 2952 2953 mode: function mode(/*a, b*/) { 2954 throw new Error('mode is not yet implemented'); 2955 }, 2956 2957 sample: function sample(a, b) { 2958 return ((a + b) / 2) + ((b - a) / 2) * 2959 Math.sin(2 * Math.PI * jStat.uniform.sample(0, 1)); 2960 }, 2961 2962 variance: function variance(a, b) { 2963 if (b <= a) return NaN; 2964 return Math.pow(b - a, 2) / 8; 2965 } 2966 }); 2967 2968 2969 function laplaceSign(x) { return x / Math.abs(x); } 2970 2971 jStat.extend(jStat.laplace, { 2972 pdf: function pdf(x, mu, b) { 2973 return (b <= 0) ? 0 : (Math.exp(-Math.abs(x - mu) / b)) / (2 * b); 2974 }, 2975 2976 cdf: function cdf(x, mu, b) { 2977 if (b <= 0) { return 0; } 2978 2979 if(x < mu) { 2980 return 0.5 * Math.exp((x - mu) / b); 2981 } else { 2982 return 1 - 0.5 * Math.exp(- (x - mu) / b); 2983 } 2984 }, 2985 2986 mean: function(mu/*, b*/) { 2987 return mu; 2988 }, 2989 2990 median: function(mu/*, b*/) { 2991 return mu; 2992 }, 2993 2994 mode: function(mu/*, b*/) { 2995 return mu; 2996 }, 2997 2998 variance: function(mu, b) { 2999 return 2 * b * b; 3000 }, 3001 3002 sample: function sample(mu, b) { 3003 var u = jStat._random_fn() - 0.5; 3004 3005 return mu - (b * laplaceSign(u) * Math.log(1 - (2 * Math.abs(u)))); 3006 } 3007 }); 3008 3009 function tukeyWprob(w, rr, cc) { 3010 var nleg = 12; 3011 var ihalf = 6; 3012 3013 var C1 = -30; 3014 var C2 = -50; 3015 var C3 = 60; 3016 var bb = 8; 3017 var wlar = 3; 3018 var wincr1 = 2; 3019 var wincr2 = 3; 3020 var xleg = [ 3021 0.981560634246719250690549090149, 3022 0.904117256370474856678465866119, 3023 0.769902674194304687036893833213, 3024 0.587317954286617447296702418941, 3025 0.367831498998180193752691536644, 3026 0.125233408511468915472441369464 3027 ]; 3028 var aleg = [ 3029 0.047175336386511827194615961485, 3030 0.106939325995318430960254718194, 3031 0.160078328543346226334652529543, 3032 0.203167426723065921749064455810, 3033 0.233492536538354808760849898925, 3034 0.249147045813402785000562436043 3035 ]; 3036 3037 var qsqz = w * 0.5; 3038 3039 // if w >= 16 then the integral lower bound (occurs for c=20) 3040 // is 0.99999999999995 so return a value of 1. 3041 3042 if (qsqz >= bb) 3043 return 1.0; 3044 3045 // find (f(w/2) - 1) ^ cc 3046 // (first term in integral of hartley's form). 3047 3048 var pr_w = 2 * jStat.normal.cdf(qsqz, 0, 1, 1, 0) - 1; // erf(qsqz / M_SQRT2) 3049 // if pr_w ^ cc < 2e-22 then set pr_w = 0 3050 if (pr_w >= Math.exp(C2 / cc)) 3051 pr_w = Math.pow(pr_w, cc); 3052 else 3053 pr_w = 0.0; 3054 3055 // if w is large then the second component of the 3056 // integral is small, so fewer intervals are needed. 3057 3058 var wincr; 3059 if (w > wlar) 3060 wincr = wincr1; 3061 else 3062 wincr = wincr2; 3063 3064 // find the integral of second term of hartley's form 3065 // for the integral of the range for equal-length 3066 // intervals using legendre quadrature. limits of 3067 // integration are from (w/2, 8). two or three 3068 // equal-length intervals are used. 3069 3070 // blb and bub are lower and upper limits of integration. 3071 3072 var blb = qsqz; 3073 var binc = (bb - qsqz) / wincr; 3074 var bub = blb + binc; 3075 var einsum = 0.0; 3076 3077 // integrate over each interval 3078 3079 var cc1 = cc - 1.0; 3080 for (var wi = 1; wi <= wincr; wi++) { 3081 var elsum = 0.0; 3082 var a = 0.5 * (bub + blb); 3083 3084 // legendre quadrature with order = nleg 3085 3086 var b = 0.5 * (bub - blb); 3087 3088 for (var jj = 1; jj <= nleg; jj++) { 3089 var j, xx; 3090 if (ihalf < jj) { 3091 j = (nleg - jj) + 1; 3092 xx = xleg[j-1]; 3093 } else { 3094 j = jj; 3095 xx = -xleg[j-1]; 3096 } 3097 var c = b * xx; 3098 var ac = a + c; 3099 3100 // if exp(-qexpo/2) < 9e-14, 3101 // then doesn't contribute to integral 3102 3103 var qexpo = ac * ac; 3104 if (qexpo > C3) 3105 break; 3106 3107 var pplus = 2 * jStat.normal.cdf(ac, 0, 1, 1, 0); 3108 var pminus= 2 * jStat.normal.cdf(ac, w, 1, 1, 0); 3109 3110 // if rinsum ^ (cc-1) < 9e-14, 3111 // then doesn't contribute to integral 3112 3113 var rinsum = (pplus * 0.5) - (pminus * 0.5); 3114 if (rinsum >= Math.exp(C1 / cc1)) { 3115 rinsum = (aleg[j-1] * Math.exp(-(0.5 * qexpo))) * Math.pow(rinsum, cc1); 3116 elsum += rinsum; 3117 } 3118 } 3119 elsum *= (((2.0 * b) * cc) / Math.sqrt(2 * Math.PI)); 3120 einsum += elsum; 3121 blb = bub; 3122 bub += binc; 3123 } 3124 3125 // if pr_w ^ rr < 9e-14, then return 0 3126 pr_w += einsum; 3127 if (pr_w <= Math.exp(C1 / rr)) 3128 return 0; 3129 3130 pr_w = Math.pow(pr_w, rr); 3131 if (pr_w >= 1) // 1 was iMax was eps 3132 return 1; 3133 return pr_w; 3134 } 3135 3136 function tukeyQinv(p, c, v) { 3137 var p0 = 0.322232421088; 3138 var q0 = 0.993484626060e-01; 3139 var p1 = -1.0; 3140 var q1 = 0.588581570495; 3141 var p2 = -0.342242088547; 3142 var q2 = 0.531103462366; 3143 var p3 = -0.204231210125; 3144 var q3 = 0.103537752850; 3145 var p4 = -0.453642210148e-04; 3146 var q4 = 0.38560700634e-02; 3147 var c1 = 0.8832; 3148 var c2 = 0.2368; 3149 var c3 = 1.214; 3150 var c4 = 1.208; 3151 var c5 = 1.4142; 3152 var vmax = 120.0; 3153 3154 var ps = 0.5 - 0.5 * p; 3155 var yi = Math.sqrt(Math.log(1.0 / (ps * ps))); 3156 var t = yi + (((( yi * p4 + p3) * yi + p2) * yi + p1) * yi + p0) 3157 / (((( yi * q4 + q3) * yi + q2) * yi + q1) * yi + q0); 3158 if (v < vmax) t += (t * t * t + t) / v / 4.0; 3159 var q = c1 - c2 * t; 3160 if (v < vmax) q += -c3 / v + c4 * t / v; 3161 return t * (q * Math.log(c - 1.0) + c5); 3162 } 3163 3164 jStat.extend(jStat.tukey, { 3165 cdf: function cdf(q, nmeans, df) { 3166 // Identical implementation as the R ptukey() function as of commit 68947 3167 var rr = 1; 3168 var cc = nmeans; 3169 3170 var nlegq = 16; 3171 var ihalfq = 8; 3172 3173 var eps1 = -30.0; 3174 var eps2 = 1.0e-14; 3175 var dhaf = 100.0; 3176 var dquar = 800.0; 3177 var deigh = 5000.0; 3178 var dlarg = 25000.0; 3179 var ulen1 = 1.0; 3180 var ulen2 = 0.5; 3181 var ulen3 = 0.25; 3182 var ulen4 = 0.125; 3183 var xlegq = [ 3184 0.989400934991649932596154173450, 3185 0.944575023073232576077988415535, 3186 0.865631202387831743880467897712, 3187 0.755404408355003033895101194847, 3188 0.617876244402643748446671764049, 3189 0.458016777657227386342419442984, 3190 0.281603550779258913230460501460, 3191 0.950125098376374401853193354250e-1 3192 ]; 3193 var alegq = [ 3194 0.271524594117540948517805724560e-1, 3195 0.622535239386478928628438369944e-1, 3196 0.951585116824927848099251076022e-1, 3197 0.124628971255533872052476282192, 3198 0.149595988816576732081501730547, 3199 0.169156519395002538189312079030, 3200 0.182603415044923588866763667969, 3201 0.189450610455068496285396723208 3202 ]; 3203 3204 if (q <= 0) 3205 return 0; 3206 3207 // df must be > 1 3208 // there must be at least two values 3209 3210 if (df < 2 || rr < 1 || cc < 2) return NaN; 3211 3212 if (!Number.isFinite(q)) 3213 return 1; 3214 3215 if (df > dlarg) 3216 return tukeyWprob(q, rr, cc); 3217 3218 // calculate leading constant 3219 3220 var f2 = df * 0.5; 3221 var f2lf = ((f2 * Math.log(df)) - (df * Math.log(2))) - jStat.gammaln(f2); 3222 var f21 = f2 - 1.0; 3223 3224 // integral is divided into unit, half-unit, quarter-unit, or 3225 // eighth-unit length intervals depending on the value of the 3226 // degrees of freedom. 3227 3228 var ff4 = df * 0.25; 3229 var ulen; 3230 if (df <= dhaf) ulen = ulen1; 3231 else if (df <= dquar) ulen = ulen2; 3232 else if (df <= deigh) ulen = ulen3; 3233 else ulen = ulen4; 3234 3235 f2lf += Math.log(ulen); 3236 3237 // integrate over each subinterval 3238 3239 var ans = 0.0; 3240 3241 for (var i = 1; i <= 50; i++) { 3242 var otsum = 0.0; 3243 3244 // legendre quadrature with order = nlegq 3245 // nodes (stored in xlegq) are symmetric around zero. 3246 3247 var twa1 = (2 * i - 1) * ulen; 3248 3249 for (var jj = 1; jj <= nlegq; jj++) { 3250 var j, t1; 3251 if (ihalfq < jj) { 3252 j = jj - ihalfq - 1; 3253 t1 = (f2lf + (f21 * Math.log(twa1 + (xlegq[j] * ulen)))) 3254 - (((xlegq[j] * ulen) + twa1) * ff4); 3255 } else { 3256 j = jj - 1; 3257 t1 = (f2lf + (f21 * Math.log(twa1 - (xlegq[j] * ulen)))) 3258 + (((xlegq[j] * ulen) - twa1) * ff4); 3259 } 3260 3261 // if exp(t1) < 9e-14, then doesn't contribute to integral 3262 var qsqz; 3263 if (t1 >= eps1) { 3264 if (ihalfq < jj) { 3265 qsqz = q * Math.sqrt(((xlegq[j] * ulen) + twa1) * 0.5); 3266 } else { 3267 qsqz = q * Math.sqrt(((-(xlegq[j] * ulen)) + twa1) * 0.5); 3268 } 3269 3270 // call wprob to find integral of range portion 3271 3272 var wprb = tukeyWprob(qsqz, rr, cc); 3273 var rotsum = (wprb * alegq[j]) * Math.exp(t1); 3274 otsum += rotsum; 3275 } 3276 // end legendre integral for interval i 3277 // L200: 3278 } 3279 3280 // if integral for interval i < 1e-14, then stop. 3281 // However, in order to avoid small area under left tail, 3282 // at least 1 / ulen intervals are calculated. 3283 if (i * ulen >= 1.0 && otsum <= eps2) 3284 break; 3285 3286 // end of interval i 3287 // L330: 3288 3289 ans += otsum; 3290 } 3291 3292 if (otsum > eps2) { // not converged 3293 throw new Error('tukey.cdf failed to converge'); 3294 } 3295 if (ans > 1) 3296 ans = 1; 3297 return ans; 3298 }, 3299 3300 inv: function(p, nmeans, df) { 3301 // Identical implementation as the R qtukey() function as of commit 68947 3302 var rr = 1; 3303 var cc = nmeans; 3304 3305 var eps = 0.0001; 3306 var maxiter = 50; 3307 3308 // df must be > 1 ; there must be at least two values 3309 if (df < 2 || rr < 1 || cc < 2) return NaN; 3310 3311 if (p < 0 || p > 1) return NaN; 3312 if (p === 0) return 0; 3313 if (p === 1) return Infinity; 3314 3315 // Initial value 3316 3317 var x0 = tukeyQinv(p, cc, df); 3318 3319 // Find prob(value < x0) 3320 3321 var valx0 = jStat.tukey.cdf(x0, nmeans, df) - p; 3322 3323 // Find the second iterate and prob(value < x1). 3324 // If the first iterate has probability value 3325 // exceeding p then second iterate is 1 less than 3326 // first iterate; otherwise it is 1 greater. 3327 3328 var x1; 3329 if (valx0 > 0.0) 3330 x1 = Math.max(0.0, x0 - 1.0); 3331 else 3332 x1 = x0 + 1.0; 3333 var valx1 = jStat.tukey.cdf(x1, nmeans, df) - p; 3334 3335 // Find new iterate 3336 3337 var ans; 3338 for(var iter = 1; iter < maxiter; iter++) { 3339 ans = x1 - ((valx1 * (x1 - x0)) / (valx1 - valx0)); 3340 valx0 = valx1; 3341 3342 // New iterate must be >= 0 3343 3344 x0 = x1; 3345 if (ans < 0.0) { 3346 ans = 0.0; 3347 valx1 = -p; 3348 } 3349 // Find prob(value < new iterate) 3350 3351 valx1 = jStat.tukey.cdf(ans, nmeans, df) - p; 3352 x1 = ans; 3353 3354 // If the difference between two successive 3355 // iterates is less than eps, stop 3356 3357 var xabs = Math.abs(x1 - x0); 3358 if (xabs < eps) 3359 return ans; 3360 } 3361 3362 throw new Error('tukey.inv failed to converge'); 3363 } 3364 }); 3365 3366 }(jStat, Math)); 3367 /* Provides functions for the solution of linear system of equations, integration, extrapolation, 3368 * interpolation, eigenvalue problems, differential equations and PCA analysis. */ 3369 3370 (function(jStat, Math) { 3371 3372 var push = Array.prototype.push; 3373 var isArray = jStat.utils.isArray; 3374 3375 function isUsable(arg) { 3376 return isArray(arg) || arg instanceof jStat; 3377 } 3378 3379 jStat.extend({ 3380 3381 // add a vector/matrix to a vector/matrix or scalar 3382 add: function add(arr, arg) { 3383 // check if arg is a vector or scalar 3384 if (isUsable(arg)) { 3385 if (!isUsable(arg[0])) arg = [ arg ]; 3386 return jStat.map(arr, function(value, row, col) { 3387 return value + arg[row][col]; 3388 }); 3389 } 3390 return jStat.map(arr, function(value) { return value + arg; }); 3391 }, 3392 3393 // subtract a vector or scalar from the vector 3394 subtract: function subtract(arr, arg) { 3395 // check if arg is a vector or scalar 3396 if (isUsable(arg)) { 3397 if (!isUsable(arg[0])) arg = [ arg ]; 3398 return jStat.map(arr, function(value, row, col) { 3399 return value - arg[row][col] || 0; 3400 }); 3401 } 3402 return jStat.map(arr, function(value) { return value - arg; }); 3403 }, 3404 3405 // matrix division 3406 divide: function divide(arr, arg) { 3407 if (isUsable(arg)) { 3408 if (!isUsable(arg[0])) arg = [ arg ]; 3409 return jStat.multiply(arr, jStat.inv(arg)); 3410 } 3411 return jStat.map(arr, function(value) { return value / arg; }); 3412 }, 3413 3414 // matrix multiplication 3415 multiply: function multiply(arr, arg) { 3416 var row, col, nrescols, sum, nrow, ncol, res, rescols; 3417 // eg: arr = 2 arg = 3 -> 6 for res[0][0] statement closure 3418 if (arr.length === undefined && arg.length === undefined) { 3419 return arr * arg; 3420 } 3421 nrow = arr.length, 3422 ncol = arr[0].length, 3423 res = jStat.zeros(nrow, nrescols = (isUsable(arg)) ? arg[0].length : ncol), 3424 rescols = 0; 3425 if (isUsable(arg)) { 3426 for (; rescols < nrescols; rescols++) { 3427 for (row = 0; row < nrow; row++) { 3428 sum = 0; 3429 for (col = 0; col < ncol; col++) 3430 sum += arr[row][col] * arg[col][rescols]; 3431 res[row][rescols] = sum; 3432 } 3433 } 3434 return (nrow === 1 && rescols === 1) ? res[0][0] : res; 3435 } 3436 return jStat.map(arr, function(value) { return value * arg; }); 3437 }, 3438 3439 // outer([1,2,3],[4,5,6]) 3440 // === 3441 // [[1],[2],[3]] times [[4,5,6]] 3442 // -> 3443 // [[4,5,6],[8,10,12],[12,15,18]] 3444 outer:function outer(A, B) { 3445 return jStat.multiply(A.map(function(t){ return [t] }), [B]); 3446 }, 3447 3448 3449 // Returns the dot product of two matricies 3450 dot: function dot(arr, arg) { 3451 if (!isUsable(arr[0])) arr = [ arr ]; 3452 if (!isUsable(arg[0])) arg = [ arg ]; 3453 // convert column to row vector 3454 var left = (arr[0].length === 1 && arr.length !== 1) ? jStat.transpose(arr) : arr, 3455 right = (arg[0].length === 1 && arg.length !== 1) ? jStat.transpose(arg) : arg, 3456 res = [], 3457 row = 0, 3458 nrow = left.length, 3459 ncol = left[0].length, 3460 sum, col; 3461 for (; row < nrow; row++) { 3462 res[row] = []; 3463 sum = 0; 3464 for (col = 0; col < ncol; col++) 3465 sum += left[row][col] * right[row][col]; 3466 res[row] = sum; 3467 } 3468 return (res.length === 1) ? res[0] : res; 3469 }, 3470 3471 // raise every element by a scalar 3472 pow: function pow(arr, arg) { 3473 return jStat.map(arr, function(value) { return Math.pow(value, arg); }); 3474 }, 3475 3476 // exponentiate every element 3477 exp: function exp(arr) { 3478 return jStat.map(arr, function(value) { return Math.exp(value); }); 3479 }, 3480 3481 // generate the natural log of every element 3482 log: function exp(arr) { 3483 return jStat.map(arr, function(value) { return Math.log(value); }); 3484 }, 3485 3486 // generate the absolute values of the vector 3487 abs: function abs(arr) { 3488 return jStat.map(arr, function(value) { return Math.abs(value); }); 3489 }, 3490 3491 // computes the p-norm of the vector 3492 // In the case that a matrix is passed, uses the first row as the vector 3493 norm: function norm(arr, p) { 3494 var nnorm = 0, 3495 i = 0; 3496 // check the p-value of the norm, and set for most common case 3497 if (isNaN(p)) p = 2; 3498 // check if multi-dimensional array, and make vector correction 3499 if (isUsable(arr[0])) arr = arr[0]; 3500 // vector norm 3501 for (; i < arr.length; i++) { 3502 nnorm += Math.pow(Math.abs(arr[i]), p); 3503 } 3504 return Math.pow(nnorm, 1 / p); 3505 }, 3506 3507 // computes the angle between two vectors in rads 3508 // In case a matrix is passed, this uses the first row as the vector 3509 angle: function angle(arr, arg) { 3510 return Math.acos(jStat.dot(arr, arg) / (jStat.norm(arr) * jStat.norm(arg))); 3511 }, 3512 3513 // augment one matrix by another 3514 // Note: this function returns a matrix, not a jStat object 3515 aug: function aug(a, b) { 3516 var newarr = []; 3517 var i; 3518 for (i = 0; i < a.length; i++) { 3519 newarr.push(a[i].slice()); 3520 } 3521 for (i = 0; i < newarr.length; i++) { 3522 push.apply(newarr[i], b[i]); 3523 } 3524 return newarr; 3525 }, 3526 3527 // The inv() function calculates the inverse of a matrix 3528 // Create the inverse by augmenting the matrix by the identity matrix of the 3529 // appropriate size, and then use G-J elimination on the augmented matrix. 3530 inv: function inv(a) { 3531 var rows = a.length; 3532 var cols = a[0].length; 3533 var b = jStat.identity(rows, cols); 3534 var c = jStat.gauss_jordan(a, b); 3535 var result = []; 3536 var i = 0; 3537 var j; 3538 3539 //We need to copy the inverse portion to a new matrix to rid G-J artifacts 3540 for (; i < rows; i++) { 3541 result[i] = []; 3542 for (j = cols; j < c[0].length; j++) 3543 result[i][j - cols] = c[i][j]; 3544 } 3545 return result; 3546 }, 3547 3548 // calculate the determinant of a matrix 3549 det: function det(a) { 3550 if (a.length === 2) { 3551 return a[0][0] * a[1][1] - a[0][1] * a[1][0]; 3552 } 3553 3554 var determinant = 0; 3555 for (var i = 0; i < a.length; i++) { 3556 // build a sub matrix without column `i` 3557 var submatrix = []; 3558 for (var row = 1; row < a.length; row++) { 3559 submatrix[row - 1] = []; 3560 for (var col = 0; col < a.length; col++) { 3561 if (col < i) { 3562 submatrix[row - 1][col] = a[row][col]; 3563 } else if (col > i) { 3564 submatrix[row - 1][col - 1] = a[row][col]; 3565 } 3566 } 3567 } 3568 3569 // alternate between + and - between determinants 3570 var sign = i % 2 ? -1 : 1; 3571 determinant += det(submatrix) * a[0][i] * sign; 3572 } 3573 3574 return determinant 3575 }, 3576 3577 gauss_elimination: function gauss_elimination(a, b) { 3578 var i = 0, 3579 j = 0, 3580 n = a.length, 3581 m = a[0].length, 3582 factor = 1, 3583 sum = 0, 3584 x = [], 3585 maug, pivot, temp, k; 3586 a = jStat.aug(a, b); 3587 maug = a[0].length; 3588 for(i = 0; i < n; i++) { 3589 pivot = a[i][i]; 3590 j = i; 3591 for (k = i + 1; k < m; k++) { 3592 if (pivot < Math.abs(a[k][i])) { 3593 pivot = a[k][i]; 3594 j = k; 3595 } 3596 } 3597 if (j != i) { 3598 for(k = 0; k < maug; k++) { 3599 temp = a[i][k]; 3600 a[i][k] = a[j][k]; 3601 a[j][k] = temp; 3602 } 3603 } 3604 for (j = i + 1; j < n; j++) { 3605 factor = a[j][i] / a[i][i]; 3606 for(k = i; k < maug; k++) { 3607 a[j][k] = a[j][k] - factor * a[i][k]; 3608 } 3609 } 3610 } 3611 for (i = n - 1; i >= 0; i--) { 3612 sum = 0; 3613 for (j = i + 1; j<= n - 1; j++) { 3614 sum = sum + x[j] * a[i][j]; 3615 } 3616 x[i] =(a[i][maug - 1] - sum) / a[i][i]; 3617 } 3618 return x; 3619 }, 3620 3621 gauss_jordan: function gauss_jordan(a, b) { 3622 var m = jStat.aug(a, b); 3623 var h = m.length; 3624 var w = m[0].length; 3625 var c = 0; 3626 var x, y, y2; 3627 // find max pivot 3628 for (y = 0; y < h; y++) { 3629 var maxrow = y; 3630 for (y2 = y+1; y2 < h; y2++) { 3631 if (Math.abs(m[y2][y]) > Math.abs(m[maxrow][y])) 3632 maxrow = y2; 3633 } 3634 var tmp = m[y]; 3635 m[y] = m[maxrow]; 3636 m[maxrow] = tmp 3637 for (y2 = y+1; y2 < h; y2++) { 3638 c = m[y2][y] / m[y][y]; 3639 for (x = y; x < w; x++) { 3640 m[y2][x] -= m[y][x] * c; 3641 } 3642 } 3643 } 3644 // backsubstitute 3645 for (y = h-1; y >= 0; y--) { 3646 c = m[y][y]; 3647 for (y2 = 0; y2 < y; y2++) { 3648 for (x = w-1; x > y-1; x--) { 3649 m[y2][x] -= m[y][x] * m[y2][y] / c; 3650 } 3651 } 3652 m[y][y] /= c; 3653 for (x = h; x < w; x++) { 3654 m[y][x] /= c; 3655 } 3656 } 3657 return m; 3658 }, 3659 3660 // solve equation 3661 // Ax=b 3662 // A is upper triangular matrix 3663 // A=[[1,2,3],[0,4,5],[0,6,7]] 3664 // b=[1,2,3] 3665 // triaUpSolve(A,b) // -> [2.666,0.1666,1.666] 3666 // if you use matrix style 3667 // A=[[1,2,3],[0,4,5],[0,6,7]] 3668 // b=[[1],[2],[3]] 3669 // will return [[2.666],[0.1666],[1.666]] 3670 triaUpSolve: function triaUpSolve(A, b) { 3671 var size = A[0].length; 3672 var x = jStat.zeros(1, size)[0]; 3673 var parts; 3674 var matrix_mode = false; 3675 3676 if (b[0].length != undefined) { 3677 b = b.map(function(i){ return i[0] }); 3678 matrix_mode = true; 3679 } 3680 3681 jStat.arange(size - 1, -1, -1).forEach(function(i) { 3682 parts = jStat.arange(i + 1, size).map(function(j) { 3683 return x[j] * A[i][j]; 3684 }); 3685 x[i] = (b[i] - jStat.sum(parts)) / A[i][i]; 3686 }); 3687 3688 if (matrix_mode) 3689 return x.map(function(i){ return [i] }); 3690 return x; 3691 }, 3692 3693 triaLowSolve: function triaLowSolve(A, b) { 3694 // like to triaUpSolve but A is lower triangular matrix 3695 var size = A[0].length; 3696 var x = jStat.zeros(1, size)[0]; 3697 var parts; 3698 3699 var matrix_mode=false; 3700 if (b[0].length != undefined) { 3701 b = b.map(function(i){ return i[0] }); 3702 matrix_mode = true; 3703 } 3704 3705 jStat.arange(size).forEach(function(i) { 3706 parts = jStat.arange(i).map(function(j) { 3707 return A[i][j] * x[j]; 3708 }); 3709 x[i] = (b[i] - jStat.sum(parts)) / A[i][i]; 3710 }) 3711 3712 if (matrix_mode) 3713 return x.map(function(i){ return [i] }); 3714 return x; 3715 }, 3716 3717 3718 // A -> [L,U] 3719 // A=LU 3720 // L is lower triangular matrix 3721 // U is upper triangular matrix 3722 lu: function lu(A) { 3723 var size = A.length; 3724 //var L=jStat.diagonal(jStat.ones(1,size)[0]); 3725 var L = jStat.identity(size); 3726 var R = jStat.zeros(A.length, A[0].length); 3727 var parts; 3728 jStat.arange(size).forEach(function(t) { 3729 R[0][t] = A[0][t]; 3730 }); 3731 jStat.arange(1, size).forEach(function(l) { 3732 jStat.arange(l).forEach(function(i) { 3733 parts = jStat.arange(i).map(function(jj) { 3734 return L[l][jj] * R[jj][i]; 3735 }); 3736 L[l][i] = (A[l][i] - jStat.sum(parts)) / R[i][i]; 3737 }); 3738 jStat.arange(l, size).forEach(function(j) { 3739 parts = jStat.arange(l).map(function(jj) { 3740 return L[l][jj] * R[jj][j]; 3741 }); 3742 R[l][j] = A[parts.length][j] - jStat.sum(parts); 3743 }); 3744 }); 3745 return [L, R]; 3746 }, 3747 3748 // A -> T 3749 // A=TT' 3750 // T is lower triangular matrix 3751 cholesky: function cholesky(A) { 3752 var size = A.length; 3753 var T = jStat.zeros(A.length, A[0].length); 3754 var parts; 3755 jStat.arange(size).forEach(function(i) { 3756 parts = jStat.arange(i).map(function(t) { 3757 return Math.pow(T[i][t],2); 3758 }); 3759 T[i][i] = Math.sqrt(A[i][i] - jStat.sum(parts)); 3760 jStat.arange(i + 1, size).forEach(function(j) { 3761 parts = jStat.arange(i).map(function(t) { 3762 return T[i][t] * T[j][t]; 3763 }); 3764 T[j][i] = (A[i][j] - jStat.sum(parts)) / T[i][i]; 3765 }); 3766 }); 3767 return T; 3768 }, 3769 3770 3771 gauss_jacobi: function gauss_jacobi(a, b, x, r) { 3772 var i = 0; 3773 var j = 0; 3774 var n = a.length; 3775 var l = []; 3776 var u = []; 3777 var d = []; 3778 var xv, c, h, xk; 3779 for (; i < n; i++) { 3780 l[i] = []; 3781 u[i] = []; 3782 d[i] = []; 3783 for (j = 0; j < n; j++) { 3784 if (i > j) { 3785 l[i][j] = a[i][j]; 3786 u[i][j] = d[i][j] = 0; 3787 } else if (i < j) { 3788 u[i][j] = a[i][j]; 3789 l[i][j] = d[i][j] = 0; 3790 } else { 3791 d[i][j] = a[i][j]; 3792 l[i][j] = u[i][j] = 0; 3793 } 3794 } 3795 } 3796 h = jStat.multiply(jStat.multiply(jStat.inv(d), jStat.add(l, u)), -1); 3797 c = jStat.multiply(jStat.inv(d), b); 3798 xv = x; 3799 xk = jStat.add(jStat.multiply(h, x), c); 3800 i = 2; 3801 while (Math.abs(jStat.norm(jStat.subtract(xk,xv))) > r) { 3802 xv = xk; 3803 xk = jStat.add(jStat.multiply(h, xv), c); 3804 i++; 3805 } 3806 return xk; 3807 }, 3808 3809 gauss_seidel: function gauss_seidel(a, b, x, r) { 3810 var i = 0; 3811 var n = a.length; 3812 var l = []; 3813 var u = []; 3814 var d = []; 3815 var j, xv, c, h, xk; 3816 for (; i < n; i++) { 3817 l[i] = []; 3818 u[i] = []; 3819 d[i] = []; 3820 for (j = 0; j < n; j++) { 3821 if (i > j) { 3822 l[i][j] = a[i][j]; 3823 u[i][j] = d[i][j] = 0; 3824 } else if (i < j) { 3825 u[i][j] = a[i][j]; 3826 l[i][j] = d[i][j] = 0; 3827 } else { 3828 d[i][j] = a[i][j]; 3829 l[i][j] = u[i][j] = 0; 3830 } 3831 } 3832 } 3833 h = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d, l)), u), -1); 3834 c = jStat.multiply(jStat.inv(jStat.add(d, l)), b); 3835 xv = x; 3836 xk = jStat.add(jStat.multiply(h, x), c); 3837 i = 2; 3838 while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) { 3839 xv = xk; 3840 xk = jStat.add(jStat.multiply(h, xv), c); 3841 i = i + 1; 3842 } 3843 return xk; 3844 }, 3845 3846 SOR: function SOR(a, b, x, r, w) { 3847 var i = 0; 3848 var n = a.length; 3849 var l = []; 3850 var u = []; 3851 var d = []; 3852 var j, xv, c, h, xk; 3853 for (; i < n; i++) { 3854 l[i] = []; 3855 u[i] = []; 3856 d[i] = []; 3857 for (j = 0; j < n; j++) { 3858 if (i > j) { 3859 l[i][j] = a[i][j]; 3860 u[i][j] = d[i][j] = 0; 3861 } else if (i < j) { 3862 u[i][j] = a[i][j]; 3863 l[i][j] = d[i][j] = 0; 3864 } else { 3865 d[i][j] = a[i][j]; 3866 l[i][j] = u[i][j] = 0; 3867 } 3868 } 3869 } 3870 h = jStat.multiply(jStat.inv(jStat.add(d, jStat.multiply(l, w))), 3871 jStat.subtract(jStat.multiply(d, 1 - w), 3872 jStat.multiply(u, w))); 3873 c = jStat.multiply(jStat.multiply(jStat.inv(jStat.add(d, 3874 jStat.multiply(l, w))), b), w); 3875 xv = x; 3876 xk = jStat.add(jStat.multiply(h, x), c); 3877 i = 2; 3878 while (Math.abs(jStat.norm(jStat.subtract(xk, xv))) > r) { 3879 xv = xk; 3880 xk = jStat.add(jStat.multiply(h, xv), c); 3881 i++; 3882 } 3883 return xk; 3884 }, 3885 3886 householder: function householder(a) { 3887 var m = a.length; 3888 var n = a[0].length; 3889 var i = 0; 3890 var w = []; 3891 var p = []; 3892 var alpha, r, k, j, factor; 3893 for (; i < m - 1; i++) { 3894 alpha = 0; 3895 for (j = i + 1; j < n; j++) 3896 alpha += (a[j][i] * a[j][i]); 3897 factor = (a[i + 1][i] > 0) ? -1 : 1; 3898 alpha = factor * Math.sqrt(alpha); 3899 r = Math.sqrt((((alpha * alpha) - a[i + 1][i] * alpha) / 2)); 3900 w = jStat.zeros(m, 1); 3901 w[i + 1][0] = (a[i + 1][i] - alpha) / (2 * r); 3902 for (k = i + 2; k < m; k++) w[k][0] = a[k][i] / (2 * r); 3903 p = jStat.subtract(jStat.identity(m, n), 3904 jStat.multiply(jStat.multiply(w, jStat.transpose(w)), 2)); 3905 a = jStat.multiply(p, jStat.multiply(a, p)); 3906 } 3907 return a; 3908 }, 3909 3910 // A -> [Q,R] 3911 // Q is orthogonal matrix 3912 // R is upper triangular 3913 QR: (function() { 3914 // x -> Q 3915 // find a orthogonal matrix Q st. 3916 // Qx=y 3917 // y is [||x||,0,0,...] 3918 3919 // quick ref 3920 var sum = jStat.sum; 3921 var range = jStat.arange; 3922 3923 function qr2(x) { 3924 // quick impletation 3925 // https://www.stat.wisc.edu/~larget/math496/qr.html 3926 3927 var n = x.length; 3928 var p = x[0].length; 3929 3930 var r = jStat.zeros(p, p); 3931 x = jStat.copy(x); 3932 3933 var i,j,k; 3934 for(j = 0; j < p; j++){ 3935 r[j][j] = Math.sqrt(sum(range(n).map(function(i){ 3936 return x[i][j] * x[i][j]; 3937 }))); 3938 for(i = 0; i < n; i++){ 3939 x[i][j] = x[i][j] / r[j][j]; 3940 } 3941 for(k = j+1; k < p; k++){ 3942 r[j][k] = sum(range(n).map(function(i){ 3943 return x[i][j] * x[i][k]; 3944 })); 3945 for(i = 0; i < n; i++){ 3946 x[i][k] = x[i][k] - x[i][j]*r[j][k]; 3947 } 3948 } 3949 } 3950 return [x, r]; 3951 } 3952 3953 return qr2; 3954 }()), 3955 3956 lstsq: (function() { 3957 // solve least squard problem for Ax=b as QR decomposition way if b is 3958 // [[b1],[b2],[b3]] form will return [[x1],[x2],[x3]] array form solution 3959 // else b is [b1,b2,b3] form will return [x1,x2,x3] array form solution 3960 function R_I(A) { 3961 A = jStat.copy(A); 3962 var size = A.length; 3963 var I = jStat.identity(size); 3964 jStat.arange(size - 1, -1, -1).forEach(function(i) { 3965 jStat.sliceAssign( 3966 I, { row: i }, jStat.divide(jStat.slice(I, { row: i }), A[i][i])); 3967 jStat.sliceAssign( 3968 A, { row: i }, jStat.divide(jStat.slice(A, { row: i }), A[i][i])); 3969 jStat.arange(i).forEach(function(j) { 3970 var c = jStat.multiply(A[j][i], -1); 3971 var Aj = jStat.slice(A, { row: j }); 3972 var cAi = jStat.multiply(jStat.slice(A, { row: i }), c); 3973 jStat.sliceAssign(A, { row: j }, jStat.add(Aj, cAi)); 3974 var Ij = jStat.slice(I, { row: j }); 3975 var cIi = jStat.multiply(jStat.slice(I, { row: i }), c); 3976 jStat.sliceAssign(I, { row: j }, jStat.add(Ij, cIi)); 3977 }) 3978 }); 3979 return I; 3980 } 3981 3982 function qr_solve(A, b){ 3983 var array_mode = false; 3984 if (b[0].length === undefined) { 3985 // [c1,c2,c3] mode 3986 b = b.map(function(x){ return [x] }); 3987 array_mode = true; 3988 } 3989 var QR = jStat.QR(A); 3990 var Q = QR[0]; 3991 var R = QR[1]; 3992 var attrs = A[0].length; 3993 var Q1 = jStat.slice(Q,{col:{end:attrs}}); 3994 var R1 = jStat.slice(R,{row:{end:attrs}}); 3995 var RI = R_I(R1); 3996 var Q2 = jStat.transpose(Q1); 3997 3998 if(Q2[0].length === undefined){ 3999 Q2 = [Q2]; // The confusing jStat.multifly implementation threat nature process again. 4000 } 4001 4002 var x = jStat.multiply(jStat.multiply(RI, Q2), b); 4003 4004 if(x.length === undefined){ 4005 x = [[x]]; // The confusing jStat.multifly implementation threat nature process again. 4006 } 4007 4008 4009 if (array_mode) 4010 return x.map(function(i){ return i[0] }); 4011 return x; 4012 } 4013 4014 return qr_solve; 4015 }()), 4016 4017 jacobi: function jacobi(a) { 4018 var condition = 1; 4019 var n = a.length; 4020 var e = jStat.identity(n, n); 4021 var ev = []; 4022 var b, i, j, p, q, maxim, theta, s; 4023 // condition === 1 only if tolerance is not reached 4024 while (condition === 1) { 4025 maxim = a[0][1]; 4026 p = 0; 4027 q = 1; 4028 for (i = 0; i < n; i++) { 4029 for (j = 0; j < n; j++) { 4030 if (i != j) { 4031 if (maxim < Math.abs(a[i][j])) { 4032 maxim = Math.abs(a[i][j]); 4033 p = i; 4034 q = j; 4035 } 4036 } 4037 } 4038 } 4039 if (a[p][p] === a[q][q]) 4040 theta = (a[p][q] > 0) ? Math.PI / 4 : -Math.PI / 4; 4041 else 4042 theta = Math.atan(2 * a[p][q] / (a[p][p] - a[q][q])) / 2; 4043 s = jStat.identity(n, n); 4044 s[p][p] = Math.cos(theta); 4045 s[p][q] = -Math.sin(theta); 4046 s[q][p] = Math.sin(theta); 4047 s[q][q] = Math.cos(theta); 4048 // eigen vector matrix 4049 e = jStat.multiply(e, s); 4050 b = jStat.multiply(jStat.multiply(jStat.inv(s), a), s); 4051 a = b; 4052 condition = 0; 4053 for (i = 1; i < n; i++) { 4054 for (j = 1; j < n; j++) { 4055 if (i != j && Math.abs(a[i][j]) > 0.001) { 4056 condition = 1; 4057 } 4058 } 4059 } 4060 } 4061 for (i = 0; i < n; i++) ev.push(a[i][i]); 4062 //returns both the eigenvalue and eigenmatrix 4063 return [e, ev]; 4064 }, 4065 4066 rungekutta: function rungekutta(f, h, p, t_j, u_j, order) { 4067 var k1, k2, u_j1, k3, k4; 4068 if (order === 2) { 4069 while (t_j <= p) { 4070 k1 = h * f(t_j, u_j); 4071 k2 = h * f(t_j + h, u_j + k1); 4072 u_j1 = u_j + (k1 + k2) / 2; 4073 u_j = u_j1; 4074 t_j = t_j + h; 4075 } 4076 } 4077 if (order === 4) { 4078 while (t_j <= p) { 4079 k1 = h * f(t_j, u_j); 4080 k2 = h * f(t_j + h / 2, u_j + k1 / 2); 4081 k3 = h * f(t_j + h / 2, u_j + k2 / 2); 4082 k4 = h * f(t_j +h, u_j + k3); 4083 u_j1 = u_j + (k1 + 2 * k2 + 2 * k3 + k4) / 6; 4084 u_j = u_j1; 4085 t_j = t_j + h; 4086 } 4087 } 4088 return u_j; 4089 }, 4090 4091 romberg: function romberg(f, a, b, order) { 4092 var i = 0; 4093 var h = (b - a) / 2; 4094 var x = []; 4095 var h1 = []; 4096 var g = []; 4097 var m, a1, j, k, I; 4098 while (i < order / 2) { 4099 I = f(a); 4100 for (j = a, k = 0; j <= b; j = j + h, k++) x[k] = j; 4101 m = x.length; 4102 for (j = 1; j < m - 1; j++) { 4103 I += (((j % 2) !== 0) ? 4 : 2) * f(x[j]); 4104 } 4105 I = (h / 3) * (I + f(b)); 4106 g[i] = I; 4107 h /= 2; 4108 i++; 4109 } 4110 a1 = g.length; 4111 m = 1; 4112 while (a1 !== 1) { 4113 for (j = 0; j < a1 - 1; j++) 4114 h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1); 4115 a1 = h1.length; 4116 g = h1; 4117 h1 = []; 4118 m++; 4119 } 4120 return g; 4121 }, 4122 4123 richardson: function richardson(X, f, x, h) { 4124 function pos(X, x) { 4125 var i = 0; 4126 var n = X.length; 4127 var p; 4128 for (; i < n; i++) 4129 if (X[i] === x) p = i; 4130 return p; 4131 } 4132 var h_min = Math.abs(x - X[pos(X, x) + 1]); 4133 var i = 0; 4134 var g = []; 4135 var h1 = []; 4136 var y1, y2, m, a, j; 4137 while (h >= h_min) { 4138 y1 = pos(X, x + h); 4139 y2 = pos(X, x); 4140 g[i] = (f[y1] - 2 * f[y2] + f[2 * y2 - y1]) / (h * h); 4141 h /= 2; 4142 i++; 4143 } 4144 a = g.length; 4145 m = 1; 4146 while (a != 1) { 4147 for (j = 0; j < a - 1; j++) 4148 h1[j] = ((Math.pow(4, m)) * g[j + 1] - g[j]) / (Math.pow(4, m) - 1); 4149 a = h1.length; 4150 g = h1; 4151 h1 = []; 4152 m++; 4153 } 4154 return g; 4155 }, 4156 4157 simpson: function simpson(f, a, b, n) { 4158 var h = (b - a) / n; 4159 var I = f(a); 4160 var x = []; 4161 var j = a; 4162 var k = 0; 4163 var i = 1; 4164 var m; 4165 for (; j <= b; j = j + h, k++) 4166 x[k] = j; 4167 m = x.length; 4168 for (; i < m - 1; i++) { 4169 I += ((i % 2 !== 0) ? 4 : 2) * f(x[i]); 4170 } 4171 return (h / 3) * (I + f(b)); 4172 }, 4173 4174 hermite: function hermite(X, F, dF, value) { 4175 var n = X.length; 4176 var p = 0; 4177 var i = 0; 4178 var l = []; 4179 var dl = []; 4180 var A = []; 4181 var B = []; 4182 var j; 4183 for (; i < n; i++) { 4184 l[i] = 1; 4185 for (j = 0; j < n; j++) { 4186 if (i != j) l[i] *= (value - X[j]) / (X[i] - X[j]); 4187 } 4188 dl[i] = 0; 4189 for (j = 0; j < n; j++) { 4190 if (i != j) dl[i] += 1 / (X [i] - X[j]); 4191 } 4192 A[i] = (1 - 2 * (value - X[i]) * dl[i]) * (l[i] * l[i]); 4193 B[i] = (value - X[i]) * (l[i] * l[i]); 4194 p += (A[i] * F[i] + B[i] * dF[i]); 4195 } 4196 return p; 4197 }, 4198 4199 lagrange: function lagrange(X, F, value) { 4200 var p = 0; 4201 var i = 0; 4202 var j, l; 4203 var n = X.length; 4204 for (; i < n; i++) { 4205 l = F[i]; 4206 for (j = 0; j < n; j++) { 4207 // calculating the lagrange polynomial L_i 4208 if (i != j) l *= (value - X[j]) / (X[i] - X[j]); 4209 } 4210 // adding the lagrange polynomials found above 4211 p += l; 4212 } 4213 return p; 4214 }, 4215 4216 cubic_spline: function cubic_spline(X, F, value) { 4217 var n = X.length; 4218 var i = 0, j; 4219 var A = []; 4220 var B = []; 4221 var alpha = []; 4222 var c = []; 4223 var h = []; 4224 var b = []; 4225 var d = []; 4226 for (; i < n - 1; i++) 4227 h[i] = X[i + 1] - X[i]; 4228 alpha[0] = 0; 4229 for (i = 1; i < n - 1; i++) { 4230 alpha[i] = (3 / h[i]) * (F[i + 1] - F[i]) - 4231 (3 / h[i-1]) * (F[i] - F[i-1]); 4232 } 4233 for (i = 1; i < n - 1; i++) { 4234 A[i] = []; 4235 B[i] = []; 4236 A[i][i-1] = h[i-1]; 4237 A[i][i] = 2 * (h[i - 1] + h[i]); 4238 A[i][i+1] = h[i]; 4239 B[i][0] = alpha[i]; 4240 } 4241 c = jStat.multiply(jStat.inv(A), B); 4242 for (j = 0; j < n - 1; j++) { 4243 b[j] = (F[j + 1] - F[j]) / h[j] - h[j] * (c[j + 1][0] + 2 * c[j][0]) / 3; 4244 d[j] = (c[j + 1][0] - c[j][0]) / (3 * h[j]); 4245 } 4246 for (j = 0; j < n; j++) { 4247 if (X[j] > value) break; 4248 } 4249 j -= 1; 4250 return F[j] + (value - X[j]) * b[j] + jStat.sq(value-X[j]) * 4251 c[j] + (value - X[j]) * jStat.sq(value - X[j]) * d[j]; 4252 }, 4253 4254 gauss_quadrature: function gauss_quadrature() { 4255 throw new Error('gauss_quadrature not yet implemented'); 4256 }, 4257 4258 PCA: function PCA(X) { 4259 var m = X.length; 4260 var n = X[0].length; 4261 var i = 0; 4262 var j, temp1; 4263 var u = []; 4264 var D = []; 4265 var result = []; 4266 var temp2 = []; 4267 var Y = []; 4268 var Bt = []; 4269 var B = []; 4270 var C = []; 4271 var V = []; 4272 var Vt = []; 4273 for (i = 0; i < m; i++) { 4274 u[i] = jStat.sum(X[i]) / n; 4275 } 4276 for (i = 0; i < n; i++) { 4277 B[i] = []; 4278 for(j = 0; j < m; j++) { 4279 B[i][j] = X[j][i] - u[j]; 4280 } 4281 } 4282 B = jStat.transpose(B); 4283 for (i = 0; i < m; i++) { 4284 C[i] = []; 4285 for (j = 0; j < m; j++) { 4286 C[i][j] = (jStat.dot([B[i]], [B[j]])) / (n - 1); 4287 } 4288 } 4289 result = jStat.jacobi(C); 4290 V = result[0]; 4291 D = result[1]; 4292 Vt = jStat.transpose(V); 4293 for (i = 0; i < D.length; i++) { 4294 for (j = i; j < D.length; j++) { 4295 if(D[i] < D[j]) { 4296 temp1 = D[i]; 4297 D[i] = D[j]; 4298 D[j] = temp1; 4299 temp2 = Vt[i]; 4300 Vt[i] = Vt[j]; 4301 Vt[j] = temp2; 4302 } 4303 } 4304 } 4305 Bt = jStat.transpose(B); 4306 for (i = 0; i < m; i++) { 4307 Y[i] = []; 4308 for (j = 0; j < Bt.length; j++) { 4309 Y[i][j] = jStat.dot([Vt[i]], [Bt[j]]); 4310 } 4311 } 4312 return [X, D, Vt, Y]; 4313 } 4314 }); 4315 4316 // extend jStat.fn with methods that require one argument 4317 (function(funcs) { 4318 for (var i = 0; i < funcs.length; i++) (function(passfunc) { 4319 jStat.fn[passfunc] = function(arg, func) { 4320 var tmpthis = this; 4321 // check for callback 4322 if (func) { 4323 setTimeout(function() { 4324 func.call(tmpthis, jStat.fn[passfunc].call(tmpthis, arg)); 4325 }, 15); 4326 return this; 4327 } 4328 if (typeof jStat[passfunc](this, arg) === 'number') 4329 return jStat[passfunc](this, arg); 4330 else 4331 return jStat(jStat[passfunc](this, arg)); 4332 }; 4333 }(funcs[i])); 4334 }('add divide multiply subtract dot pow exp log abs norm angle'.split(' '))); 4335 4336 }(jStat, Math)); 4337 (function(jStat, Math) { 4338 4339 var slice = [].slice; 4340 var isNumber = jStat.utils.isNumber; 4341 var isArray = jStat.utils.isArray; 4342 4343 // flag==true denotes use of sample standard deviation 4344 // Z Statistics 4345 jStat.extend({ 4346 // 2 different parameter lists: 4347 // (value, mean, sd) 4348 // (value, array, flag) 4349 zscore: function zscore() { 4350 var args = slice.call(arguments); 4351 if (isNumber(args[1])) { 4352 return (args[0] - args[1]) / args[2]; 4353 } 4354 return (args[0] - jStat.mean(args[1])) / jStat.stdev(args[1], args[2]); 4355 }, 4356 4357 // 3 different paramter lists: 4358 // (value, mean, sd, sides) 4359 // (zscore, sides) 4360 // (value, array, sides, flag) 4361 ztest: function ztest() { 4362 var args = slice.call(arguments); 4363 var z; 4364 if (isArray(args[1])) { 4365 // (value, array, sides, flag) 4366 z = jStat.zscore(args[0],args[1],args[3]); 4367 return (args[2] === 1) ? 4368 (jStat.normal.cdf(-Math.abs(z), 0, 1)) : 4369 (jStat.normal.cdf(-Math.abs(z), 0, 1)*2); 4370 } else { 4371 if (args.length > 2) { 4372 // (value, mean, sd, sides) 4373 z = jStat.zscore(args[0],args[1],args[2]); 4374 return (args[3] === 1) ? 4375 (jStat.normal.cdf(-Math.abs(z),0,1)) : 4376 (jStat.normal.cdf(-Math.abs(z),0,1)* 2); 4377 } else { 4378 // (zscore, sides) 4379 z = args[0]; 4380 return (args[1] === 1) ? 4381 (jStat.normal.cdf(-Math.abs(z),0,1)) : 4382 (jStat.normal.cdf(-Math.abs(z),0,1)*2); 4383 } 4384 } 4385 } 4386 }); 4387 4388 jStat.extend(jStat.fn, { 4389 zscore: function zscore(value, flag) { 4390 return (value - this.mean()) / this.stdev(flag); 4391 }, 4392 4393 ztest: function ztest(value, sides, flag) { 4394 var zscore = Math.abs(this.zscore(value, flag)); 4395 return (sides === 1) ? 4396 (jStat.normal.cdf(-zscore, 0, 1)) : 4397 (jStat.normal.cdf(-zscore, 0, 1) * 2); 4398 } 4399 }); 4400 4401 // T Statistics 4402 jStat.extend({ 4403 // 2 parameter lists 4404 // (value, mean, sd, n) 4405 // (value, array) 4406 tscore: function tscore() { 4407 var args = slice.call(arguments); 4408 return (args.length === 4) ? 4409 ((args[0] - args[1]) / (args[2] / Math.sqrt(args[3]))) : 4410 ((args[0] - jStat.mean(args[1])) / 4411 (jStat.stdev(args[1], true) / Math.sqrt(args[1].length))); 4412 }, 4413 4414 // 3 different paramter lists: 4415 // (value, mean, sd, n, sides) 4416 // (tscore, n, sides) 4417 // (value, array, sides) 4418 ttest: function ttest() { 4419 var args = slice.call(arguments); 4420 var tscore; 4421 if (args.length === 5) { 4422 tscore = Math.abs(jStat.tscore(args[0], args[1], args[2], args[3])); 4423 return (args[4] === 1) ? 4424 (jStat.studentt.cdf(-tscore, args[3]-1)) : 4425 (jStat.studentt.cdf(-tscore, args[3]-1)*2); 4426 } 4427 if (isNumber(args[1])) { 4428 tscore = Math.abs(args[0]) 4429 return (args[2] == 1) ? 4430 (jStat.studentt.cdf(-tscore, args[1]-1)) : 4431 (jStat.studentt.cdf(-tscore, args[1]-1) * 2); 4432 } 4433 tscore = Math.abs(jStat.tscore(args[0], args[1])) 4434 return (args[2] == 1) ? 4435 (jStat.studentt.cdf(-tscore, args[1].length-1)) : 4436 (jStat.studentt.cdf(-tscore, args[1].length-1) * 2); 4437 } 4438 }); 4439 4440 jStat.extend(jStat.fn, { 4441 tscore: function tscore(value) { 4442 return (value - this.mean()) / (this.stdev(true) / Math.sqrt(this.cols())); 4443 }, 4444 4445 ttest: function ttest(value, sides) { 4446 return (sides === 1) ? 4447 (1 - jStat.studentt.cdf(Math.abs(this.tscore(value)), this.cols()-1)) : 4448 (jStat.studentt.cdf(-Math.abs(this.tscore(value)), this.cols()-1)*2); 4449 } 4450 }); 4451 4452 // F Statistics 4453 jStat.extend({ 4454 // Paramter list is as follows: 4455 // (array1, array2, array3, ...) 4456 // or it is an array of arrays 4457 // array of arrays conversion 4458 anovafscore: function anovafscore() { 4459 var args = slice.call(arguments), 4460 expVar, sample, sampMean, sampSampMean, tmpargs, unexpVar, i, j; 4461 if (args.length === 1) { 4462 tmpargs = new Array(args[0].length); 4463 for (i = 0; i < args[0].length; i++) { 4464 tmpargs[i] = args[0][i]; 4465 } 4466 args = tmpargs; 4467 } 4468 // Builds sample array 4469 sample = new Array(); 4470 for (i = 0; i < args.length; i++) { 4471 sample = sample.concat(args[i]); 4472 } 4473 sampMean = jStat.mean(sample); 4474 // Computes the explained variance 4475 expVar = 0; 4476 for (i = 0; i < args.length; i++) { 4477 expVar = expVar + args[i].length * Math.pow(jStat.mean(args[i]) - sampMean, 2); 4478 } 4479 expVar /= (args.length - 1); 4480 // Computes unexplained variance 4481 unexpVar = 0; 4482 for (i = 0; i < args.length; i++) { 4483 sampSampMean = jStat.mean(args[i]); 4484 for (j = 0; j < args[i].length; j++) { 4485 unexpVar += Math.pow(args[i][j] - sampSampMean, 2); 4486 } 4487 } 4488 unexpVar /= (sample.length - args.length); 4489 return expVar / unexpVar; 4490 }, 4491 4492 // 2 different paramter setups 4493 // (array1, array2, array3, ...) 4494 // (anovafscore, df1, df2) 4495 anovaftest: function anovaftest() { 4496 var args = slice.call(arguments), 4497 df1, df2, n, i; 4498 if (isNumber(args[0])) { 4499 return 1 - jStat.centralF.cdf(args[0], args[1], args[2]); 4500 } 4501 var anovafscore = jStat.anovafscore(args); 4502 df1 = args.length - 1; 4503 n = 0; 4504 for (i = 0; i < args.length; i++) { 4505 n = n + args[i].length; 4506 } 4507 df2 = n - df1 - 1; 4508 return 1 - jStat.centralF.cdf(anovafscore, df1, df2); 4509 }, 4510 4511 ftest: function ftest(fscore, df1, df2) { 4512 return 1 - jStat.centralF.cdf(fscore, df1, df2); 4513 } 4514 }); 4515 4516 jStat.extend(jStat.fn, { 4517 anovafscore: function anovafscore() { 4518 return jStat.anovafscore(this.toArray()); 4519 }, 4520 4521 anovaftes: function anovaftes() { 4522 var n = 0; 4523 var i; 4524 for (i = 0; i < this.length; i++) { 4525 n = n + this[i].length; 4526 } 4527 return jStat.ftest(this.anovafscore(), this.length - 1, n - this.length); 4528 } 4529 }); 4530 4531 // Tukey's range test 4532 jStat.extend({ 4533 // 2 parameter lists 4534 // (mean1, mean2, n1, n2, sd) 4535 // (array1, array2, sd) 4536 qscore: function qscore() { 4537 var args = slice.call(arguments); 4538 var mean1, mean2, n1, n2, sd; 4539 if (isNumber(args[0])) { 4540 mean1 = args[0]; 4541 mean2 = args[1]; 4542 n1 = args[2]; 4543 n2 = args[3]; 4544 sd = args[4]; 4545 } else { 4546 mean1 = jStat.mean(args[0]); 4547 mean2 = jStat.mean(args[1]); 4548 n1 = args[0].length; 4549 n2 = args[1].length; 4550 sd = args[2]; 4551 } 4552 return Math.abs(mean1 - mean2) / (sd * Math.sqrt((1 / n1 + 1 / n2) / 2)); 4553 }, 4554 4555 // 3 different parameter lists: 4556 // (qscore, n, k) 4557 // (mean1, mean2, n1, n2, sd, n, k) 4558 // (array1, array2, sd, n, k) 4559 qtest: function qtest() { 4560 var args = slice.call(arguments); 4561 4562 var qscore; 4563 if (args.length === 3) { 4564 qscore = args[0]; 4565 args = args.slice(1); 4566 } else if (args.length === 7) { 4567 qscore = jStat.qscore(args[0], args[1], args[2], args[3], args[4]); 4568 args = args.slice(5); 4569 } else { 4570 qscore = jStat.qscore(args[0], args[1], args[2]); 4571 args = args.slice(3); 4572 } 4573 4574 var n = args[0]; 4575 var k = args[1]; 4576 4577 return 1 - jStat.tukey.cdf(qscore, k, n - k); 4578 }, 4579 4580 tukeyhsd: function tukeyhsd(arrays) { 4581 var sd = jStat.pooledstdev(arrays); 4582 var means = arrays.map(function (arr) {return jStat.mean(arr);}); 4583 var n = arrays.reduce(function (n, arr) {return n + arr.length;}, 0); 4584 4585 var results = []; 4586 for (var i = 0; i < arrays.length; ++i) { 4587 for (var j = i + 1; j < arrays.length; ++j) { 4588 var p = jStat.qtest(means[i], means[j], arrays[i].length, arrays[j].length, sd, n, arrays.length); 4589 results.push([[i, j], p]); 4590 } 4591 } 4592 4593 return results; 4594 } 4595 }); 4596 4597 // Error Bounds 4598 jStat.extend({ 4599 // 2 different parameter setups 4600 // (value, alpha, sd, n) 4601 // (value, alpha, array) 4602 normalci: function normalci() { 4603 var args = slice.call(arguments), 4604 ans = new Array(2), 4605 change; 4606 if (args.length === 4) { 4607 change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) * 4608 args[2] / Math.sqrt(args[3])); 4609 } else { 4610 change = Math.abs(jStat.normal.inv(args[1] / 2, 0, 1) * 4611 jStat.stdev(args[2]) / Math.sqrt(args[2].length)); 4612 } 4613 ans[0] = args[0] - change; 4614 ans[1] = args[0] + change; 4615 return ans; 4616 }, 4617 4618 // 2 different parameter setups 4619 // (value, alpha, sd, n) 4620 // (value, alpha, array) 4621 tci: function tci() { 4622 var args = slice.call(arguments), 4623 ans = new Array(2), 4624 change; 4625 if (args.length === 4) { 4626 change = Math.abs(jStat.studentt.inv(args[1] / 2, args[3] - 1) * 4627 args[2] / Math.sqrt(args[3])); 4628 } else { 4629 change = Math.abs(jStat.studentt.inv(args[1] / 2, args[2].length - 1) * 4630 jStat.stdev(args[2], true) / Math.sqrt(args[2].length)); 4631 } 4632 ans[0] = args[0] - change; 4633 ans[1] = args[0] + change; 4634 return ans; 4635 }, 4636 4637 significant: function significant(pvalue, alpha) { 4638 return pvalue < alpha; 4639 } 4640 }); 4641 4642 jStat.extend(jStat.fn, { 4643 normalci: function normalci(value, alpha) { 4644 return jStat.normalci(value, alpha, this.toArray()); 4645 }, 4646 4647 tci: function tci(value, alpha) { 4648 return jStat.tci(value, alpha, this.toArray()); 4649 } 4650 }); 4651 4652 // internal method for calculating the z-score for a difference of proportions test 4653 function differenceOfProportions(p1, n1, p2, n2) { 4654 if (p1 > 1 || p2 > 1 || p1 <= 0 || p2 <= 0) { 4655 throw new Error("Proportions should be greater than 0 and less than 1") 4656 } 4657 var pooled = (p1 * n1 + p2 * n2) / (n1 + n2); 4658 var se = Math.sqrt(pooled * (1 - pooled) * ((1/n1) + (1/n2))); 4659 return (p1 - p2) / se; 4660 } 4661 4662 // Difference of Proportions 4663 jStat.extend(jStat.fn, { 4664 oneSidedDifferenceOfProportions: function oneSidedDifferenceOfProportions(p1, n1, p2, n2) { 4665 var z = differenceOfProportions(p1, n1, p2, n2); 4666 return jStat.ztest(z, 1); 4667 }, 4668 4669 twoSidedDifferenceOfProportions: function twoSidedDifferenceOfProportions(p1, n1, p2, n2) { 4670 var z = differenceOfProportions(p1, n1, p2, n2); 4671 return jStat.ztest(z, 2); 4672 } 4673 }); 4674 4675 }(jStat, Math)); 4676 jStat.models = (function(){ 4677 function sub_regress(exog) { 4678 var var_count = exog[0].length; 4679 var modelList = jStat.arange(var_count).map(function(endog_index) { 4680 var exog_index = 4681 jStat.arange(var_count).filter(function(i){return i!==endog_index}); 4682 return ols(jStat.col(exog, endog_index).map(function(x){ return x[0] }), 4683 jStat.col(exog, exog_index)) 4684 }); 4685 return modelList; 4686 } 4687 4688 // do OLS model regress 4689 // exog have include const columns ,it will not generate it .In fact, exog is 4690 // "design matrix" look at 4691 //https://en.wikipedia.org/wiki/Design_matrix 4692 function ols(endog, exog) { 4693 var nobs = endog.length; 4694 var df_model = exog[0].length - 1; 4695 var df_resid = nobs-df_model - 1; 4696 var coef = jStat.lstsq(exog, endog); 4697 var predict = 4698 jStat.multiply(exog, coef.map(function(x) { return [x] })) 4699 .map(function(p) { return p[0] }); 4700 var resid = jStat.subtract(endog, predict); 4701 var ybar = jStat.mean(endog); 4702 // constant cause problem 4703 // var SST = jStat.sum(endog.map(function(y) { 4704 // return Math.pow(y-ybar,2); 4705 // })); 4706 var SSE = jStat.sum(predict.map(function(f) { 4707 return Math.pow(f - ybar, 2); 4708 })); 4709 var SSR = jStat.sum(endog.map(function(y, i) { 4710 return Math.pow(y - predict[i], 2); 4711 })); 4712 var SST = SSE + SSR; 4713 var R2 = (SSE / SST); 4714 return { 4715 exog:exog, 4716 endog:endog, 4717 nobs:nobs, 4718 df_model:df_model, 4719 df_resid:df_resid, 4720 coef:coef, 4721 predict:predict, 4722 resid:resid, 4723 ybar:ybar, 4724 SST:SST, 4725 SSE:SSE, 4726 SSR:SSR, 4727 R2:R2 4728 }; 4729 } 4730 4731 // H0: b_I=0 4732 // H1: b_I!=0 4733 function t_test(model) { 4734 var subModelList = sub_regress(model.exog); 4735 //var sigmaHat=jStat.stdev(model.resid); 4736 var sigmaHat = Math.sqrt(model.SSR / (model.df_resid)); 4737 var seBetaHat = subModelList.map(function(mod) { 4738 var SST = mod.SST; 4739 var R2 = mod.R2; 4740 return sigmaHat / Math.sqrt(SST * (1 - R2)); 4741 }); 4742 var tStatistic = model.coef.map(function(coef, i) { 4743 return (coef - 0) / seBetaHat[i]; 4744 }); 4745 var pValue = tStatistic.map(function(t) { 4746 var leftppf = jStat.studentt.cdf(t, model.df_resid); 4747 return (leftppf > 0.5 ? 1 - leftppf : leftppf) * 2; 4748 }); 4749 var c = jStat.studentt.inv(0.975, model.df_resid); 4750 var interval95 = model.coef.map(function(coef, i) { 4751 var d = c * seBetaHat[i]; 4752 return [coef - d, coef + d]; 4753 }) 4754 return { 4755 se: seBetaHat, 4756 t: tStatistic, 4757 p: pValue, 4758 sigmaHat: sigmaHat, 4759 interval95: interval95 4760 }; 4761 } 4762 4763 function F_test(model) { 4764 var F_statistic = 4765 (model.R2 / model.df_model) / ((1 - model.R2) / model.df_resid); 4766 var fcdf = function(x, n1, n2) { 4767 return jStat.beta.cdf(x / (n2 / n1 + x), n1 / 2, n2 / 2) 4768 } 4769 var pvalue = 1 - fcdf(F_statistic, model.df_model, model.df_resid); 4770 return { F_statistic: F_statistic, pvalue: pvalue }; 4771 } 4772 4773 function ols_wrap(endog, exog) { 4774 var model = ols(endog,exog); 4775 var ttest = t_test(model); 4776 var ftest = F_test(model); 4777 // Provide the Wherry / Ezekiel / McNemar / Cohen Adjusted R^2 4778 // Which matches the 'adjusted R^2' provided by R's lm package 4779 var adjust_R2 = 4780 1 - (1 - model.R2) * ((model.nobs - 1) / (model.df_resid)); 4781 model.t = ttest; 4782 model.f = ftest; 4783 model.adjust_R2 = adjust_R2; 4784 return model; 4785 } 4786 4787 return { ols: ols_wrap }; 4788 })(); 4789 //To regress, simply build X matrix 4790 //(append column of 1's) using 4791 //buildxmatrix and build the Y 4792 //matrix using buildymatrix 4793 //(simply the transpose) 4794 //and run regress. 4795 4796 4797 4798 //Regressions 4799 4800 jStat.extend({ 4801 buildxmatrix: function buildxmatrix(){ 4802 //Parameters will be passed in as such 4803 //(array1,array2,array3,...) 4804 //as (x1,x2,x3,...) 4805 //needs to be (1,x1,x2,x3,...) 4806 var matrixRows = new Array(arguments.length); 4807 for(var i=0;i<arguments.length;i++){ 4808 var array = [1]; 4809 matrixRows[i]= array.concat(arguments[i]); 4810 } 4811 return jStat(matrixRows); 4812 4813 }, 4814 4815 builddxmatrix: function builddxmatrix() { 4816 //Paramters will be passed in as such 4817 //([array1,array2,...] 4818 var matrixRows = new Array(arguments[0].length); 4819 for(var i=0;i<arguments[0].length;i++){ 4820 var array = [1] 4821 matrixRows[i]= array.concat(arguments[0][i]); 4822 } 4823 return jStat(matrixRows); 4824 4825 }, 4826 4827 buildjxmatrix: function buildjxmatrix(jMat) { 4828 //Builds from jStat Matrix 4829 var pass = new Array(jMat.length) 4830 for(var i=0;i<jMat.length;i++){ 4831 pass[i] = jMat[i]; 4832 } 4833 return jStat.builddxmatrix(pass); 4834 4835 }, 4836 4837 buildymatrix: function buildymatrix(array){ 4838 return jStat(array).transpose(); 4839 }, 4840 4841 buildjymatrix: function buildjymatrix(jMat){ 4842 return jMat.transpose(); 4843 }, 4844 4845 matrixmult: function matrixmult(A,B){ 4846 var i, j, k, result, sum; 4847 if (A.cols() == B.rows()) { 4848 if(B.rows()>1){ 4849 result = []; 4850 for (i = 0; i < A.rows(); i++) { 4851 result[i] = []; 4852 for (j = 0; j < B.cols(); j++) { 4853 sum = 0; 4854 for (k = 0; k < A.cols(); k++) { 4855 sum += A.toArray()[i][k] * B.toArray()[k][j]; 4856 } 4857 result[i][j] = sum; 4858 } 4859 } 4860 return jStat(result); 4861 } 4862 result = []; 4863 for (i = 0; i < A.rows(); i++) { 4864 result[i] = []; 4865 for (j = 0; j < B.cols(); j++) { 4866 sum = 0; 4867 for (k = 0; k < A.cols(); k++) { 4868 sum += A.toArray()[i][k] * B.toArray()[j]; 4869 } 4870 result[i][j] = sum; 4871 } 4872 } 4873 return jStat(result); 4874 } 4875 }, 4876 4877 //regress and regresst to be fixed 4878 4879 regress: function regress(jMatX,jMatY){ 4880 //print("regressin!"); 4881 //print(jMatX.toArray()); 4882 var innerinv = jStat.xtranspxinv(jMatX); 4883 //print(innerinv); 4884 var xtransp = jMatX.transpose(); 4885 var next = jStat.matrixmult(jStat(innerinv),xtransp); 4886 return jStat.matrixmult(next,jMatY); 4887 4888 }, 4889 4890 regresst: function regresst(jMatX,jMatY,sides){ 4891 var beta = jStat.regress(jMatX,jMatY); 4892 4893 var compile = {}; 4894 compile.anova = {}; 4895 var jMatYBar = jStat.jMatYBar(jMatX, beta); 4896 compile.yBar = jMatYBar; 4897 var yAverage = jMatY.mean(); 4898 compile.anova.residuals = jStat.residuals(jMatY, jMatYBar); 4899 4900 compile.anova.ssr = jStat.ssr(jMatYBar, yAverage); 4901 compile.anova.msr = compile.anova.ssr / (jMatX[0].length - 1); 4902 4903 compile.anova.sse = jStat.sse(jMatY, jMatYBar); 4904 compile.anova.mse = 4905 compile.anova.sse / (jMatY.length - (jMatX[0].length - 1) - 1); 4906 4907 compile.anova.sst = jStat.sst(jMatY, yAverage); 4908 compile.anova.mst = compile.anova.sst / (jMatY.length - 1); 4909 4910 compile.anova.r2 = 1 - (compile.anova.sse / compile.anova.sst); 4911 if (compile.anova.r2 < 0) compile.anova.r2 = 0; 4912 4913 compile.anova.fratio = compile.anova.msr / compile.anova.mse; 4914 compile.anova.pvalue = 4915 jStat.anovaftest(compile.anova.fratio, 4916 jMatX[0].length - 1, 4917 jMatY.length - (jMatX[0].length - 1) - 1); 4918 4919 compile.anova.rmse = Math.sqrt(compile.anova.mse); 4920 4921 compile.anova.r2adj = 1 - (compile.anova.mse / compile.anova.mst); 4922 if (compile.anova.r2adj < 0) compile.anova.r2adj = 0; 4923 4924 compile.stats = new Array(jMatX[0].length); 4925 var covar = jStat.xtranspxinv(jMatX); 4926 var sds, ts, ps; 4927 4928 for(var i=0; i<beta.length;i++){ 4929 sds=Math.sqrt(compile.anova.mse * Math.abs(covar[i][i])); 4930 ts= Math.abs(beta[i] / sds); 4931 ps= jStat.ttest(ts, jMatY.length - jMatX[0].length - 1, sides); 4932 4933 compile.stats[i]=[beta[i], sds, ts, ps]; 4934 } 4935 4936 compile.regress = beta; 4937 return compile; 4938 }, 4939 4940 xtranspx: function xtranspx(jMatX){ 4941 return jStat.matrixmult(jMatX.transpose(),jMatX); 4942 }, 4943 4944 4945 xtranspxinv: function xtranspxinv(jMatX){ 4946 var inner = jStat.matrixmult(jMatX.transpose(),jMatX); 4947 var innerinv = jStat.inv(inner); 4948 return innerinv; 4949 }, 4950 4951 jMatYBar: function jMatYBar(jMatX, beta) { 4952 var yBar = jStat.matrixmult(jMatX, beta); 4953 return new jStat(yBar); 4954 }, 4955 4956 residuals: function residuals(jMatY, jMatYBar) { 4957 return jStat.matrixsubtract(jMatY, jMatYBar); 4958 }, 4959 4960 ssr: function ssr(jMatYBar, yAverage) { 4961 var ssr = 0; 4962 for(var i = 0; i < jMatYBar.length; i++) { 4963 ssr += Math.pow(jMatYBar[i] - yAverage, 2); 4964 } 4965 return ssr; 4966 }, 4967 4968 sse: function sse(jMatY, jMatYBar) { 4969 var sse = 0; 4970 for(var i = 0; i < jMatY.length; i++) { 4971 sse += Math.pow(jMatY[i] - jMatYBar[i], 2); 4972 } 4973 return sse; 4974 }, 4975 4976 sst: function sst(jMatY, yAverage) { 4977 var sst = 0; 4978 for(var i = 0; i < jMatY.length; i++) { 4979 sst += Math.pow(jMatY[i] - yAverage, 2); 4980 } 4981 return sst; 4982 }, 4983 4984 matrixsubtract: function matrixsubtract(A,B){ 4985 var ans = new Array(A.length); 4986 for(var i=0;i<A.length;i++){ 4987 ans[i] = new Array(A[i].length); 4988 for(var j=0;j<A[i].length;j++){ 4989 ans[i][j]=A[i][j]-B[i][j]; 4990 } 4991 } 4992 return jStat(ans); 4993 } 4994 }); 4995 // Make it compatible with previous version. 4996 jStat.jStat = jStat; 4997 4998 return jStat; 4999 });