123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
- Available via Academic Free License >= 2.1 OR the modified BSD license.
- see: http://dojotoolkit.org/license for details
- */
- if(!dojo._hasResource["dojox.math.stats"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
- dojo._hasResource["dojox.math.stats"] = true;
- dojo.provide("dojox.math.stats");
- dojo.getObject("math.stats", true, dojox);
- (function(){
- var st = dojox.math.stats;
- dojo.mixin(st, {
- sd: function(/* Number[] */a){
- // summary:
- // Returns the standard deviation of the passed arguments.
- return Math.sqrt(st.variance(a)); // Number
- },
- variance: function(/* Number[] */a){
- // summary:
- // Find the variance in the passed array of numbers.
- var mean=0, squares=0;
- dojo.forEach(a, function(item){
- mean+=item;
- squares+=Math.pow(item,2);
- });
- return (squares/a.length)-Math.pow(mean/a.length, 2); // Number
- },
- bestFit: function(/* Object[] || Number[] */a, /* String? */xProp, /* String? */yProp){
- // summary:
- // Calculate the slope and intercept in a linear fashion. An array
- // of objects is expected; optionally you can pass in the property
- // names for "x" and "y", else x/y is used as the default. If you
- // pass an array of numbers, it will be mapped to a set of {x,y} objects
- // where x = the array index.
- xProp = xProp || "x", yProp = yProp || "y";
- if(a[0] !== undefined && typeof(a[0]) == "number"){
- // this is an array of numbers, so use the index as x.
- a = dojo.map(a, function(item, idx){
- return { x: idx, y: item };
- });
- }
- var sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0, stt = 0, sts = 0, n = a.length, t;
- for(var i=0; i<n; i++){
- sx += a[i][xProp];
- sy += a[i][yProp];
- sxx += Math.pow(a[i][xProp], 2);
- syy += Math.pow(a[i][yProp], 2);
- sxy += a[i][xProp] * a[i][yProp];
- }
- // we use the following because it's more efficient and accurate for determining the slope.
- for(i=0; i<n; i++){
- t = a[i][xProp] - sx/n;
- stt += t*t;
- sts += t*a[i][yProp];
- }
- var slope = sts/(stt||1); // prevent divide by zero.
- // get Pearson's R
- var d = Math.sqrt((sxx - Math.pow(sx,2)/n) * (syy - Math.pow(sy,2)/n));
- if(d === 0){
- throw new Error("dojox.math.stats.bestFit: the denominator for Pearson's R is 0.");
- }
- var r = (sxy-(sx*sy/n)) / d;
- var r2 = Math.pow(r, 2);
- if(slope < 0){
- r = -r;
- }
- // to use: y = slope*x + intercept;
- return { // Object
- slope: slope,
- intercept: (sy - sx*slope)/(n||1),
- r: r,
- r2: r2
- };
- },
- forecast: function(/* Object[] || Number[] */a, /* Number */x, /* String? */xProp, /* String? */yProp){
- // summary:
- // Using the bestFit algorithm above, find y for the given x.
- var fit = st.bestFit(a, xProp, yProp);
- return (fit.slope * x) + fit.intercept; // Number
- },
- mean: function(/* Number[] */a){
- // summary:
- // Returns the mean value in the passed array.
- var t=0;
- dojo.forEach(a, function(v){
- t += v;
- });
- return t / Math.max(a.length, 1); // Number
- },
- min: function(/* Number[] */a){
- // summary:
- // Returns the min value in the passed array.
- return Math.min.apply(null, a); // Number
- },
- max: function(/* Number[] */a){
- // summary:
- // Returns the max value in the passed array.
- return Math.max.apply(null, a); // Number
- },
- median: function(/* Number[] */a){
- // summary:
- // Returns the value closest to the middle from a sorted version of the passed array.
- var t = a.slice(0).sort(function(a, b){ return a - b; });
- return (t[Math.floor(a.length/2)] + t[Math.ceil(a.length/2)])/2; // Number
- },
- mode: function(/* Number[] */a){
- // summary:
- // Returns the mode from the passed array (number that appears the most often).
- // This is not the most efficient method, since it requires a double scan, but
- // is ensures accuracy.
- var o = {}, r = 0, m = Number.MIN_VALUE;
- dojo.forEach(a, function(v){
- (o[v]!==undefined)?o[v]++:o[v]=1;
- });
- // we did the lookup map because we need the number that appears the most.
- for(var p in o){
- if(m < o[p]){
- m = o[p], r = p;
- }
- }
- return r; // Number
- },
- sum: function(/* Number[] */a){
- // summary:
- // Return the sum of all the numbers in the passed array. Does
- // not check to make sure values within a are NaN (should simply
- // return NaN).
- var sum = 0;
- dojo.forEach(a, function(n){
- sum += n;
- });
- return sum; // Number
- },
- approxLin: function(a, pos){
- // summary:
- // Returns a linearly approximated value from an array using
- // a normalized float position value.
- // a: Number[]:
- // a sorted numeric array to be used for the approximation.
- // pos: Number:
- // a position number from 0 to 1. If outside of this range it
- // will be clamped.
- // returns: Number
- var p = pos * (a.length - 1), t = Math.ceil(p), f = t - 1;
- if(f < 0){ return a[0]; }
- if(t >= a.length){ return a[a.length - 1]; }
- return a[f] * (t - p) + a[t] * (p - f); // Number
- },
- summary: function(a, alreadySorted){
- // summary:
- // Returns a non-parametric collection of summary statistics:
- // the classic five-number summary extended to the Bowley's
- // seven-figure summary.
- // a: Number[]:
- // a numeric array to be appraised.
- // alreadySorted: Boolean?:
- // a Boolean flag to indicated that the array is already sorted.
- // This is an optional flag purely to improve the performance.
- // If skipped, the array will be assumed unsorted.
- // returns: Object
- if(!alreadySorted){
- a = a.slice(0); // copy the array
- a.sort(function(a, b){ return a - b; }); // sort it properly
- }
- var l = st.approxLin,
- result = {
- // the five-number summary
- min: a[0], // minimum
- p25: l(a, 0.25), // lower quartile
- med: l(a, 0.5), // median
- p75: l(a, 0.75), // upper quartile
- max: a[a.length - 1], // maximum
- // extended to the Bowley's seven-figure summary
- p10: l(a, 0.1), // first decile
- p90: l(a, 0.9) // last decile
- };
- return result; // Object
- }
- });
- })();
- }
|