math.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /**
  2. * Simple Javascript eXtension - 1.0, Mathematics Module
  3. * (c) 2011 - 2015 Steve L. Nyemba, steve@the-phi.com
  4. * License GPL version 3.0
  5. *
  6. * dependencies:
  7. * utils.js implementation of design patterns and utilities
  8. *
  9. * This file contains an enhancement of utilities integrated into the jx.math.* built-in package of javascript
  10. * Because we implement math and numerical functions it is to be understood that most of the functions will have common preconditions
  11. * i.e lxi.constructor == Array && isNumber(lxi) unless specified otherwise
  12. * jx.math.max
  13. * jx.math.min
  14. * jx.math.sum
  15. * jx.math.prod
  16. * jx.math.freq
  17. * jx.math.avg
  18. * jx.math.mean computes the mean/average of a list of observations (arthmetic mean included too)
  19. * jx.math.sd computes the standard deviation of a list of observations
  20. * jx.math.var computes the variance of a list of observations
  21. * jx.math.diff computes the absolute difference of values in an array
  22. * jx.math.fibonacci comptutes the fibonacci value of a given number
  23. * jx.math.factorial computes the factorial of a given number
  24. */
  25. if(!jx){
  26. var jx = {} ;
  27. }
  28. jx.math = {}
  29. jx.math.sqrt = Math.sqrt;
  30. jx.math.PHI = (1+jx.math.sqrt(5))/2 ;//1.61803399 ;
  31. /**
  32. * @param lxi list of observatins xi
  33. */
  34. jx.math.max = function(lxi){
  35. sortNumber= function(a,b) {
  36. return a - b;
  37. }
  38. index = lxi.length -1 ;
  39. max = jx.utils.cast(lxi,Number).sort(sortNumber)[index] ; // perhaps need to cast
  40. return max ;
  41. }
  42. /**
  43. * finds the minimum of a list of observation lxi (vector of values)
  44. * @param lxi list/vector of values/observations
  45. */
  46. jx.math.min = function(lxi){
  47. sortNumber = function(a,b){
  48. return a- b;
  49. }
  50. min = jx.utils.cast(lxi,Number).sort(sortNumber)[0] ;
  51. return min ;
  52. }
  53. /**
  54. * @pre : values.constructor == Array
  55. * @param lxi list of observed values to be summed
  56. */
  57. jx.math.sum = function(lxi){
  58. return eval(lxi.join('+'));
  59. } ;
  60. /**
  61. * This function will compute the frequency of a vector i.e providing relative values
  62. */
  63. jx.math.freq = function(lxi){
  64. var N = jx.math.sum(lxi) ;
  65. return jx.utils.patterns.visitor(lxi,function(xi){
  66. return xi/N ;
  67. });
  68. }
  69. /**
  70. * This function will perform the product of a vector
  71. * @pre lxi.constructor == Array && isNumber(lxi)
  72. */
  73. jx.math.prod = function(lxi){
  74. return eval(lxi.join('*')) ;
  75. }
  76. /**
  77. * @pre : lni != null && lxi.length == lni.length
  78. * @param lxi list of observed values
  79. * @param lni list of the number of times observations of index i have been made
  80. */
  81. jx.math.avg = function(lxi,lni){
  82. N = lxi.length ;
  83. if(lni == null){
  84. return jx.math.sum(lxi)/N ;
  85. }else{
  86. values = []
  87. for(var i=0; i < lxi.length; i++){
  88. values[i] = Number(lxi[i])*Number(lni[i]) ;
  89. }
  90. return Number(jx.math.sum(values)/N) ;
  91. }
  92. };
  93. /**
  94. * This function will repete a value a given number of times
  95. * @pre times > 0
  96. */
  97. jx.math.rep = function(value,times){
  98. var lvalues = []
  99. for(var i=0; i < times; i++){
  100. lvalues.push(value) ;
  101. }
  102. return lvalues;
  103. }
  104. jx.math.mean = jx.math.avg ;
  105. /**
  106. * This function will compute the mode of a given vector
  107. * The mode is by definition the most frequent item in the vector
  108. */
  109. jx.math.mode = function(x) {
  110. var N = x.length ;
  111. map = {}
  112. var max =0;
  113. var value = 0;
  114. for(var i in x){
  115. id = x[i] ;
  116. if(map[id] == null){
  117. map[id] = 0 ;
  118. }
  119. map[id] = map[id] + 1 ;
  120. if(map[id] > max){
  121. value = id ;
  122. max = map[id] ;
  123. }
  124. }
  125. var value = jx.utils.patterns.visitor(jx.utils.keys(map),function(id){
  126. if(map[id] == max){
  127. return Number(id) ;
  128. }else{
  129. return null;
  130. }
  131. })
  132. return value.length == 1?value[0]:value ;
  133. }
  134. jx.math.pow = Math.pow
  135. jx.math.sd = function(lxi,lni){
  136. N = lxi.length ;
  137. mean = jx.math.mean(lxi,lni) ;
  138. sqr = [] ;
  139. for(var i=0; i < lxi.length ;i++){
  140. sqr[i] = jx.math.pow((Number(lxi[i])-mean),2 ) ;
  141. }
  142. total = jx.math.sum(sqr);
  143. return jx.math.sqrt(total/(N-1)) ;
  144. } ;
  145. /**
  146. * This function computes the correlation between two vectors
  147. * @pre x1.length == x2.length
  148. */
  149. jx.math.cor = function(x1,x2){
  150. return jx.math.cov(x1,x2) / (jx.math.sd(x1)*jx.math.sd(x2))
  151. }
  152. /**
  153. * This function will compute the covariance of 2 vectors
  154. * @pre x1.length == x2.length
  155. */
  156. jx.math.cov = function(x1,x2){
  157. var u1 = jx.math.mean(x1) ;
  158. var u2 = jx.math.mean(x2) ;
  159. var N = x1.length ;
  160. var value = 0
  161. for(var i in x1){
  162. value += (x1[i] - u1) * (x2[i] - u2)
  163. }
  164. return value / (N - 1)
  165. }
  166. /**
  167. * Computes the factorial of a given value
  168. */
  169. jx.math.factorial = function(value){
  170. r =value;
  171. for(var i =value-1; i > 0; i--){
  172. r *= i ;
  173. }
  174. return r;
  175. } ;
  176. /**
  177. * Computes the fibonacci value of a given number using the golden ratio
  178. */
  179. jx.math.fibonacci = function(value){
  180. r = (jx.math.pow(jx.math.PHI,value)/jx.math.sqrt(5)) + 0.5 ;
  181. return jx.math.floor(r) ;
  182. } ;
  183. /**
  184. * computes the absolute difference of values in a list of observations
  185. */
  186. jx.math.diff = function(lxi){
  187. var r = [] ;
  188. var x,y;
  189. for(var i=0; i < lxi.length-1; i++){
  190. x = lxi[i] ;
  191. y = lxi[i+1] ;
  192. r.push(y-x)
  193. }
  194. return r ;
  195. };
  196. /**
  197. * This section implements a few handlers based on sets
  198. */
  199. jx.math.sets = {} ;
  200. /**
  201. * This function will perform a unique operation of values/objects
  202. * @param list list/vector of values or objects
  203. * @param equals operator to be used, only provide this for complex objects
  204. */
  205. jx.math.sets.unique = jx.utils.unique ;
  206. /**
  207. * This function will perform the union of 2 sets (objects, or values)
  208. * @param list1 list/vector of values or objects
  209. * @param list2 list/vector of values or objects
  210. * @param equals operator to be used to evaluate equality (use this for complex objects)
  211. */
  212. jx.math.sets.union = function(list1,list2,equals){
  213. runion = [] ;
  214. runion = list1.concat(list2) ;
  215. runion = jx.math.sets.unique(runion,equals)
  216. return runion;
  217. }
  218. /**
  219. * This function will normalize values within a vector
  220. * By definition normalization is (x - u) / sd (assuming population parameters are known)
  221. */
  222. jx.math.normalize = function(lvalues){
  223. mean = jx.math.mean(lvalues) ;
  224. sd = jx.math.sd(lvalues) ;
  225. return jx.utils.patterns.visitor(lvalues,function(x){
  226. return ((x - mean) / sd)
  227. })
  228. }
  229. /**
  230. * This function will scale a feature vector over it's range
  231. */
  232. jx.math.scale = function(lvalues,percent){
  233. max = jx.math.max(lvalues) ;
  234. min = jx.math.min(lvalues) ;
  235. return jx.utils.patterns.visitor(lvalues,function(x){
  236. var value = (x - min ) / max ;
  237. if(percent == true){
  238. return (100*value).toFixed(2)
  239. }else{
  240. return value ;
  241. }
  242. })
  243. }
  244. /**
  245. * This is a lightweight map reduce infrastructure
  246. */
  247. jx.mr = {} ;
  248. /**
  249. * This function will perform a map on a given id in rec, then will call emit with the
  250. */
  251. jx.mr.map = null
  252. /**
  253. * @param keys
  254. * @param values array of values that were mapped
  255. */
  256. jx.mr.reduce = null;
  257. jx.mr.mapreduce = function(data,fn_map,fn_reduce){
  258. if (fn_map == null){
  259. throw new "Map function is not defined"
  260. }
  261. map = {} ;
  262. emit = function(id,values){
  263. if(map[id] == null){
  264. map[id] = []
  265. }
  266. map[id].push(values);
  267. }
  268. if(data.constructor != Array){
  269. for (id in data){
  270. //rec = data[id] ;
  271. rec = {}
  272. rec['__id'] = id;
  273. rec['data'] = data[id] ;
  274. fn_map(rec,emit)
  275. }
  276. }else{
  277. for (var i=0; i < data.length; i++){
  278. rec = data[i];
  279. fn_map(rec,emit);
  280. //if(i == 2)break;
  281. }
  282. }
  283. if(fn_reduce != null){
  284. keys = jx.utils.keys(map) ;
  285. m = {}
  286. for(var i=0; i < keys.length; i++){
  287. id = keys[i] ;
  288. values = map[id] ;
  289. value = fn_reduce(id,values) ;
  290. id = keys[i] ;
  291. m[id] = value;
  292. }
  293. map = m
  294. }
  295. return map ;
  296. }