source: Dev/branches/rest-dojo-ui/client/dojox/math/stats.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

File size: 5.8 KB
Line 
1// AMD-ID "dojox/math/stats"
2define(["dojo", "../main"], function(dojo, dojox) {
3       
4        dojo.getObject("math.stats", true, dojox);
5
6        var st = dojox.math.stats;
7        dojo.mixin(st, {
8                sd: function(/* Number[] */a){
9                        //      summary:
10                        //              Returns the standard deviation of the passed arguments.
11                        return Math.sqrt(st.variance(a));       //      Number
12                },
13
14                variance: function(/* Number[] */a){
15                        //      summary:
16                        //              Find the variance in the passed array of numbers.
17                        var mean=0, squares=0;
18                        dojo.forEach(a, function(item){
19                                mean+=item;
20                                squares+=Math.pow(item,2);
21                        });
22                        return (squares/a.length)-Math.pow(mean/a.length, 2);   //      Number
23                },
24
25                bestFit: function(/* Object[] || Number[] */a, /* String? */xProp, /* String? */yProp){
26                        //      summary:
27                        //              Calculate the slope and intercept in a linear fashion.  An array
28                        //              of objects is expected; optionally you can pass in the property
29                        //              names for "x" and "y", else x/y is used as the default.  If you
30                        //              pass an array of numbers, it will be mapped to a set of {x,y} objects
31                        //              where x = the array index.
32                        xProp = xProp || "x", yProp = yProp || "y";
33                        if(a[0] !== undefined && typeof(a[0]) == "number"){
34                                //      this is an array of numbers, so use the index as x.
35                                a = dojo.map(a, function(item, idx){
36                                        return { x: idx, y: item };
37                                });
38                        }
39
40                        var sx = 0, sy = 0, sxx = 0, syy = 0, sxy = 0, stt = 0, sts = 0, n = a.length, t;
41                        for(var i=0; i<n; i++){
42                                sx += a[i][xProp];
43                                sy += a[i][yProp];
44                                sxx += Math.pow(a[i][xProp], 2);
45                                syy += Math.pow(a[i][yProp], 2);
46                                sxy += a[i][xProp] * a[i][yProp];
47                        }
48
49                        //      we use the following because it's more efficient and accurate for determining the slope.
50                        for(i=0; i<n; i++){
51                                t = a[i][xProp] - sx/n;
52                                stt += t*t;
53                                sts += t*a[i][yProp];
54                        }
55                        var slope = sts/(stt||1);       //      prevent divide by zero.
56
57                        //      get Pearson's R
58                        var d = Math.sqrt((sxx - Math.pow(sx,2)/n) * (syy - Math.pow(sy,2)/n));
59                        if(d === 0){
60                                throw new Error("dojox.math.stats.bestFit: the denominator for Pearson's R is 0.");
61                        }
62
63                        var r = (sxy-(sx*sy/n)) / d;
64                        var r2 = Math.pow(r, 2);
65                        if(slope < 0){
66                                r = -r;
67                        }
68
69                        //      to use:  y = slope*x + intercept;
70                        return {        //      Object
71                                slope: slope,
72                                intercept: (sy - sx*slope)/(n||1),
73                                r: r,
74                                r2: r2
75                        };
76                },
77
78                forecast: function(/* Object[] || Number[] */a, /* Number */x, /* String? */xProp, /* String? */yProp){
79                        //      summary:
80                        //              Using the bestFit algorithm above, find y for the given x.
81                        var fit = st.bestFit(a, xProp, yProp);
82                        return (fit.slope * x) + fit.intercept; //      Number
83                },
84
85                mean: function(/* Number[] */a){
86                        //      summary:
87                        //              Returns the mean value in the passed array.
88                        var t=0;
89                        dojo.forEach(a, function(v){
90                                t += v;
91                        });
92                        return t / Math.max(a.length, 1);       //      Number
93                },
94
95                min: function(/* Number[] */a){
96                        //      summary:
97                        //              Returns the min value in the passed array.
98                        return Math.min.apply(null, a);         //      Number
99                },
100
101                max: function(/* Number[] */a){
102                        //      summary:
103                        //              Returns the max value in the passed array.
104                        return Math.max.apply(null, a);         //      Number
105                },
106
107                median: function(/* Number[] */a){
108                        //      summary:
109                        //              Returns the value closest to the middle from a sorted version of the passed array.
110                        var t = a.slice(0).sort(function(a, b){ return a - b; });
111                        return (t[Math.floor(a.length/2)] + t[Math.ceil(a.length/2)])/2; // Number
112                },
113
114                mode: function(/* Number[] */a){
115                        //      summary:
116                        //              Returns the mode from the passed array (number that appears the most often).
117                        //              This is not the most efficient method, since it requires a double scan, but
118                        //              is ensures accuracy.
119                        var o = {}, r = 0, m = Number.MIN_VALUE;
120                        dojo.forEach(a, function(v){
121                                (o[v]!==undefined)?o[v]++:o[v]=1;
122                        });
123
124                        //      we did the lookup map because we need the number that appears the most.
125                        for(var p in o){
126                                if(m < o[p]){
127                                        m = o[p], r = p;
128                                }
129                        }
130                        return r;       //      Number
131                },
132
133                sum: function(/* Number[] */a){
134                        //      summary:
135                        //              Return the sum of all the numbers in the passed array.  Does
136                        //              not check to make sure values within a are NaN (should simply
137                        //              return NaN).
138                        var sum = 0;
139                        dojo.forEach(a, function(n){
140                                sum += n;
141                        });
142                        return sum;     //      Number
143                },
144
145                approxLin: function(a, pos){
146                        //      summary:
147                        //              Returns a linearly approximated value from an array using
148                        //              a normalized float position value.
149                        //      a: Number[]:
150                        //              a sorted numeric array to be used for the approximation.
151                        //      pos: Number:
152                        //              a position number from 0 to 1. If outside of this range it
153                        //              will be clamped.
154                        //      returns: Number
155                        var p = pos * (a.length - 1), t = Math.ceil(p), f = t - 1;
156                        if(f < 0){ return a[0]; }
157                        if(t >= a.length){ return a[a.length - 1]; }
158                        return a[f] * (t - p) + a[t] * (p - f); // Number
159                },
160
161                summary: function(a, alreadySorted){
162                        //      summary:
163                        //              Returns a non-parametric collection of summary statistics:
164                        //              the classic five-number summary extended to the Bowley's
165                        //              seven-figure summary.
166                        //      a: Number[]:
167                        //              a numeric array to be appraised.
168                        //      alreadySorted: Boolean?:
169                        //              a Boolean flag to indicated that the array is already sorted.
170                        //              This is an optional flag purely to improve the performance.
171                        //              If skipped, the array will be assumed unsorted.
172                        //      returns: Object
173                        if(!alreadySorted){
174                                a = a.slice(0);                                                         // copy the array
175                                a.sort(function(a, b){ return a - b; });        // sort it properly
176                        }
177                        var     l = st.approxLin,
178                                result = {
179                                        // the five-number summary
180                                        min:    a[0],                           // minimum
181                                        p25:    l(a, 0.25),                     // lower quartile
182                                        med:    l(a, 0.5),                      // median
183                                        p75:    l(a, 0.75),                     // upper quartile
184                                        max:    a[a.length - 1],        // maximum
185                                        // extended to the Bowley's seven-figure summary
186                                        p10:    l(a, 0.1),                      // first decile
187                                        p90:    l(a, 0.9)                       // last decile
188                                };
189                        return result;  // Object
190                }
191        });
192
193        return dojox.math.stats;
194});
Note: See TracBrowser for help on using the repository browser.