123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- /**
- * Simple Javascript eXtension - 1.0, Mathematics Module
- * (c) 2011 - 2015 Steve L. Nyemba, steve@the-phi.com
- * License GPL version 3.0
- *
- * dependencies:
- * utils.js implementation of design patterns and utilities
- *
- * This file contains an enhancement of utilities integrated into the jx.math.* built-in package of javascript
- * Because we implement math and numerical functions it is to be understood that most of the functions will have common preconditions
- * i.e lxi.constructor == Array && isNumber(lxi) unless specified otherwise
- * jx.math.max
- * jx.math.min
- * jx.math.sum
- * jx.math.prod
- * jx.math.freq
- * jx.math.avg
- * jx.math.mean computes the mean/average of a list of observations (arthmetic mean included too)
- * jx.math.sd computes the standard deviation of a list of observations
- * jx.math.var computes the variance of a list of observations
- * jx.math.diff computes the absolute difference of values in an array
- * jx.math.fibonacci comptutes the fibonacci value of a given number
- * jx.math.factorial computes the factorial of a given number
- */
- if(!jx){
- var jx = {} ;
- }
- jx.math = {}
- jx.math.sqrt = Math.sqrt;
- jx.math.PHI = (1+jx.math.sqrt(5))/2 ;//1.61803399 ;
- /**
- * @param lxi list of observatins xi
- */
- jx.math.max = function(lxi){
- sortNumber= function(a,b) {
- return a - b;
- }
- index = lxi.length -1 ;
- max = jx.utils.cast(lxi,Number).sort(sortNumber)[index] ; // perhaps need to cast
- return max ;
- }
- /**
- * finds the minimum of a list of observation lxi (vector of values)
- * @param lxi list/vector of values/observations
- */
- jx.math.min = function(lxi){
- sortNumber = function(a,b){
- return a- b;
- }
- min = jx.utils.cast(lxi,Number).sort(sortNumber)[0] ;
- return min ;
- }
- /**
- * @pre : values.constructor == Array
- * @param lxi list of observed values to be summed
- */
- jx.math.sum = function(lxi){
- return eval(lxi.join('+'));
- } ;
- /**
- * This function will compute the frequency of a vector i.e providing relative values
- */
- jx.math.freq = function(lxi){
- var N = jx.math.sum(lxi) ;
- return jx.utils.patterns.visitor(lxi,function(xi){
- return xi/N ;
- });
- }
- /**
- * This function will perform the product of a vector
- * @pre lxi.constructor == Array && isNumber(lxi)
- */
- jx.math.prod = function(lxi){
- return eval(lxi.join('*')) ;
- }
- /**
- * @pre : lni != null && lxi.length == lni.length
- * @param lxi list of observed values
- * @param lni list of the number of times observations of index i have been made
- */
- jx.math.avg = function(lxi,lni){
- N = lxi.length ;
- if(lni == null){
- return jx.math.sum(lxi)/N ;
- }else{
- values = []
- for(var i=0; i < lxi.length; i++){
- values[i] = Number(lxi[i])*Number(lni[i]) ;
- }
- return Number(jx.math.sum(values)/N) ;
- }
- };
- /**
- * This function will repete a value a given number of times
- * @pre times > 0
- */
- jx.math.rep = function(value,times){
- var lvalues = []
- for(var i=0; i < times; i++){
- lvalues.push(value) ;
- }
- return lvalues;
- }
- jx.math.mean = jx.math.avg ;
- /**
- * This function will compute the mode of a given vector
- * The mode is by definition the most frequent item in the vector
- */
- jx.math.mode = function(x) {
- var N = x.length ;
- map = {}
- var max =0;
- var value = 0;
- for(var i in x){
- id = x[i] ;
- if(map[id] == null){
- map[id] = 0 ;
- }
- map[id] = map[id] + 1 ;
- if(map[id] > max){
- value = id ;
- max = map[id] ;
- }
- }
- var value = jx.utils.patterns.visitor(jx.utils.keys(map),function(id){
- if(map[id] == max){
- return Number(id) ;
- }else{
- return null;
- }
- })
- return value.length == 1?value[0]:value ;
- }
- jx.math.pow = Math.pow
- jx.math.sd = function(lxi,lni){
- N = lxi.length ;
- mean = jx.math.mean(lxi,lni) ;
- sqr = [] ;
- for(var i=0; i < lxi.length ;i++){
- sqr[i] = jx.math.pow((Number(lxi[i])-mean),2 ) ;
- }
- total = jx.math.sum(sqr);
- return jx.math.sqrt(total/(N-1)) ;
- } ;
- /**
- * This function computes the correlation between two vectors
- * @pre x1.length == x2.length
- */
- jx.math.cor = function(x1,x2){
- return jx.math.cov(x1,x2) / (jx.math.sd(x1)*jx.math.sd(x2))
- }
- /**
- * This function will compute the covariance of 2 vectors
- * @pre x1.length == x2.length
- */
- jx.math.cov = function(x1,x2){
- var u1 = jx.math.mean(x1) ;
- var u2 = jx.math.mean(x2) ;
- var N = x1.length ;
- var value = 0
- for(var i in x1){
- value += (x1[i] - u1) * (x2[i] - u2)
- }
- return value / (N - 1)
- }
- /**
- * Computes the factorial of a given value
- */
- jx.math.factorial = function(value){
- r =value;
- for(var i =value-1; i > 0; i--){
- r *= i ;
- }
- return r;
- } ;
- /**
- * Computes the fibonacci value of a given number using the golden ratio
- */
- jx.math.fibonacci = function(value){
- r = (jx.math.pow(jx.math.PHI,value)/jx.math.sqrt(5)) + 0.5 ;
- return jx.math.floor(r) ;
- } ;
- /**
- * computes the absolute difference of values in a list of observations
- */
- jx.math.diff = function(lxi){
- var r = [] ;
- var x,y;
- for(var i=0; i < lxi.length-1; i++){
- x = lxi[i] ;
- y = lxi[i+1] ;
- r.push(y-x)
- }
- return r ;
- };
- /**
- * This section implements a few handlers based on sets
- */
- jx.math.sets = {} ;
- /**
- * This function will perform a unique operation of values/objects
- * @param list list/vector of values or objects
- * @param equals operator to be used, only provide this for complex objects
- */
- jx.math.sets.unique = jx.utils.unique ;
- /**
- * This function will perform the union of 2 sets (objects, or values)
- * @param list1 list/vector of values or objects
- * @param list2 list/vector of values or objects
- * @param equals operator to be used to evaluate equality (use this for complex objects)
- */
- jx.math.sets.union = function(list1,list2,equals){
- runion = [] ;
- runion = list1.concat(list2) ;
- runion = jx.math.sets.unique(runion,equals)
- return runion;
- }
- /**
- * This function will normalize values within a vector
- * By definition normalization is (x - u) / sd (assuming population parameters are known)
- */
- jx.math.normalize = function(lvalues){
- mean = jx.math.mean(lvalues) ;
- sd = jx.math.sd(lvalues) ;
- return jx.utils.patterns.visitor(lvalues,function(x){
- return ((x - mean) / sd)
- })
- }
- /**
- * This function will scale a feature vector over it's range
- */
- jx.math.scale = function(lvalues,percent){
- max = jx.math.max(lvalues) ;
- min = jx.math.min(lvalues) ;
- return jx.utils.patterns.visitor(lvalues,function(x){
- var value = (x - min ) / max ;
- if(percent == true){
- return (100*value).toFixed(2)
- }else{
- return value ;
- }
- })
- }
- /**
- * This is a lightweight map reduce infrastructure
- */
- jx.mr = {} ;
- /**
- * This function will perform a map on a given id in rec, then will call emit with the
- */
- jx.mr.map = null
- /**
- * @param keys
- * @param values array of values that were mapped
- */
- jx.mr.reduce = null;
- jx.mr.mapreduce = function(data,fn_map,fn_reduce){
- if (fn_map == null){
- throw new "Map function is not defined"
- }
- map = {} ;
- emit = function(id,values){
- if(map[id] == null){
- map[id] = []
- }
- map[id].push(values);
- }
- if(data.constructor != Array){
- for (id in data){
- //rec = data[id] ;
- rec = {}
- rec['__id'] = id;
- rec['data'] = data[id] ;
- fn_map(rec,emit)
- }
- }else{
- for (var i=0; i < data.length; i++){
- rec = data[i];
- fn_map(rec,emit);
- //if(i == 2)break;
- }
- }
- if(fn_reduce != null){
- keys = jx.utils.keys(map) ;
- m = {}
- for(var i=0; i < keys.length; i++){
- id = keys[i] ;
- values = map[id] ;
- value = fn_reduce(id,values) ;
- id = keys[i] ;
- m[id] = value;
- }
- map = m
- }
- return map ;
- }
|