simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

variance.js (5726B)


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