source: Dev/trunk/src/client/dojox/math/stats.js @ 529

Last change on this file since 529 was 483, checked in by hendrikvanantwerpen, 11 years ago

Added Dojo 1.9.3 release.

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.