| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 | 'use strict';function isArray(x) {  return Array.isArray(x) || ArrayBuffer.isView(x) && !(x instanceof DataView);}function Summary(data, sorted) {  if (!(this instanceof Summary)) return new Summary(data, sorted);  if (!isArray(data)) {    throw TypeError('data must be an array');  }  this._data = data;  this._sorted = sorted ? data : null;  this._length = data.length;  this._cache_sum = null;  this._cache_mode = null;  this._cache_mean = null;  this._cache_quartiles = {};  this._cache_variance = null;  this._cache_sd = null;  this._cache_max = null;  this._cache_min = null;}module.exports = Summary;//// Not all values are in lazy calculated since that wouldn't do any good//Summary.prototype.data = function() {  return this._data;};Summary.prototype.sort = function() {  if (this._sorted === null) {    this._sorted = this._data.slice(0).sort(function (a, b) { return a - b; });  }  return this._sorted;};Summary.prototype.size = function () {  return this._length;};//// Always lazy calculated functions//Summary.prototype.sum = function () {  if (this._cache_sum === null) {    // Numerically stable sum    // https://en.m.wikipedia.org/wiki/Pairwise_summation    const partials = [];    for (let i = 0; i < this._length; i++) {      partials.push(this._data[i]);      for (let j = i; j % 2 == 1; j = j >> 1) {        const p = partials.pop();        const q = partials.pop();        partials.push(p + q);      }    }    let total = 0.0;    for (let i = 0; i < partials.length; i++) {      total += partials[i];    }    this._cache_sum = total;  }  return this._cache_sum;};Summary.prototype.mode = function () {  if (this._cache_mode === null) {    const data = this.sort();    let modeValue = NaN;    let modeCount = 0;    let currValue = data[0];    let currCount = 1;    // Count the amount of repeat and update mode variables    for (let i = 1; i < this._length; i++) {      if (data[i] === currValue) {        currCount += 1;      } else {        if (currCount >= modeCount) {          modeCount = currCount;          modeValue = currValue;        }        currValue = data[i];        currCount = 1;      }    }    // Check the last count    if (currCount >= modeCount) {      modeCount = currCount;      modeValue = currValue;    }    this._cache_mode = modeValue;  }  return this._cache_mode;};Summary.prototype.mean = function () {  if (this._cache_mean === null) {    // Numerically stable mean algorithm    let mean = 0;    for (let i = 0; i < this._length; i++) {        mean += (this._data[i] - mean) / (i+1);    }    this._cache_mean = mean;  }  return this._cache_mean;};Summary.prototype.quartile = function (prob) {  if (!this._cache_quartiles.hasOwnProperty(prob)) {    const data = this.sort();    const product = prob * this.size();    const ceil = Math.ceil(product);    if (ceil === product) {      if (ceil === 0) {        this._cache_quartiles[prob] = data[0];      } else if (ceil === data.length) {        this._cache_quartiles[prob] = data[data.length - 1];      } else {        this._cache_quartiles[prob] = (data[ceil - 1] + data[ceil]) / 2;      }    } else {      this._cache_quartiles[prob] = data[ceil - 1];    }  }  return this._cache_quartiles[prob];};Summary.prototype.median = function () {  return this.quartile(0.5);};Summary.prototype.variance = function () {  if (this._cache_variance === null) {    // Numerically stable variance algorithm    const mean = this.mean();    let biasedVariance = 0;    for (let i = 0; i < this._length; i++) {      const diff = this._data[i] - mean;      biasedVariance += (diff * diff - biasedVariance) / (i+1);    }    // Debias the variance    const debiasTerm = ((this._length) / (this._length - 1));    this._cache_variance = biasedVariance * debiasTerm;  }  return this._cache_variance;};Summary.prototype.sd = function () {  if (this._cache_sd === null) {    this._cache_sd = Math.sqrt(this.variance());  }  return this._cache_sd;};Summary.prototype.max = function () {  if (this._cache_max === null) {    this._cache_max = this.sort()[this._length - 1];  }  return this._cache_max;};Summary.prototype.min = function () {  if (this._cache_min === null) {    this._cache_min = this.sort()[0];  }  return this._cache_min;};
 |