KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jfree > data > statistics > Statistics


1 /* ===========================================================
2  * JFreeChart : a free chart library for the Java(tm) platform
3  * ===========================================================
4  *
5  * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
6  *
7  * Project Info: http://www.jfree.org/jfreechart/index.html
8  *
9  * This library is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 of the License, or
12  * (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17  * License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this library; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
22  *
23  * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
24  * in the United States and other countries.]
25  *
26  * ---------------
27  * Statistics.java
28  * ---------------
29  * (C) Copyright 2000-2005, by Matthew Wright and Contributors.
30  *
31  * Original Author: Matthew Wright;
32  * Contributor(s): David Gilbert (for Object Refinery Limited);
33  *
34  * $Id: Statistics.java,v 1.5 2005/03/29 12:57:13 mungady Exp $
35  *
36  * Changes (from 08-Nov-2001)
37  * --------------------------
38  * 08-Nov-2001 : Added standard header and tidied Javadoc comments (DG);
39  * Moved from JFreeChart to package com.jrefinery.data.* in
40  * JCommon class library (DG);
41  * 24-Jun-2002 : Removed unnecessary local variable (DG);
42  * 07-Oct-2002 : Fixed errors reported by Checkstyle (DG);
43  * 26-May-2004 : Moved calculateMean() method from BoxAndWhiskerCalculator (DG);
44  * 02-Jun-2004 : Fixed bug in calculateMedian() method (DG);
45  * 11-Jan-2005 : Removed deprecated code in preparation for the 1.0.0
46  * release (DG);
47  *
48  */

49
50 package org.jfree.data.statistics;
51
52 import java.util.ArrayList JavaDoc;
53 import java.util.Collection JavaDoc;
54 import java.util.Collections JavaDoc;
55 import java.util.Iterator JavaDoc;
56 import java.util.List JavaDoc;
57
58 /**
59  * A utility class that provides some simple statistical functions.
60  */

61 public abstract class Statistics {
62
63     /**
64      * Returns the mean of an array of numbers.
65      *
66      * @param values the values (<code>null</code> permitted, returns
67      * <code>Double.NaN</code>).
68      *
69      * @return The mean.
70      */

71     public static double calculateMean(Number JavaDoc[] values) {
72         double result = Double.NaN;
73         if (values != null && values.length > 0) {
74             double sum = 0.0;
75             int counter = 0;
76             for (; counter < values.length; counter++) {
77                 sum = sum + values[counter].doubleValue();
78             }
79             result = (sum / counter);
80         }
81         return result;
82     }
83
84     /**
85      * Returns the mean of a collection of <code>Number</code> objects.
86      *
87      * @param values the values (<code>null</code> permitted, returns
88      * <code>Double.NaN</code>).
89      *
90      * @return The mean.
91      */

92     public static double calculateMean(Collection JavaDoc values) {
93         
94         double result = Double.NaN;
95         int count = 0;
96         double total = 0.0;
97         Iterator JavaDoc iterator = values.iterator();
98         while (iterator.hasNext()) {
99             Object JavaDoc object = iterator.next();
100             if (object != null && object instanceof Number JavaDoc) {
101                 Number JavaDoc number = (Number JavaDoc) object;
102                 total = total + number.doubleValue();
103                 count = count + 1;
104             }
105         }
106         if (count > 0) {
107             result = total / count;
108         }
109         return result;
110         
111     }
112     
113     /**
114      * Calculates the median for a list of values (<code>Number</code> objects).
115      * The list of values will be sorted first.
116      *
117      * @param values the values.
118      *
119      * @return The median.
120      */

121     public static double calculateMedian(List JavaDoc values) {
122         return calculateMedian(values, true);
123     }
124     
125     /**
126      * Calculates the median for a list of values (<code>Number</code> objects)
127      * that are assumed to be in ascending order.
128      *
129      * @param values the values.
130      * @param copyAndSort a flag that controls whether the list of values is
131      * copied and sorted.
132      *
133      * @return The median.
134      */

135     public static double calculateMedian(List JavaDoc values, boolean copyAndSort) {
136         
137         double result = Double.NaN;
138         if (values != null) {
139             if (copyAndSort) {
140                 int itemCount = values.size();
141                 List JavaDoc copy = new ArrayList JavaDoc(itemCount);
142                 for (int i = 0; i < itemCount; i++) {
143                     copy.add(i, values.get(i));
144                 }
145                 Collections.sort(copy);
146                 values = copy;
147             }
148             int count = values.size();
149             if (count > 0) {
150                 if (count % 2 == 1) {
151                     if (count > 1) {
152                         Number JavaDoc value = (Number JavaDoc) values.get((count - 1) / 2);
153                         result = value.doubleValue();
154                     }
155                     else {
156                         Number JavaDoc value = (Number JavaDoc) values.get(0);
157                         result = value.doubleValue();
158                     }
159                 }
160                 else {
161                     Number JavaDoc value1 = (Number JavaDoc) values.get(count / 2 - 1);
162                     Number JavaDoc value2 = (Number JavaDoc) values.get(count / 2);
163                     result = (value1.doubleValue() + value2.doubleValue())
164                              / 2.0;
165                 }
166             }
167         }
168         return result;
169     }
170     
171     /**
172      * Calculates the median for a sublist within a list of values
173      * (<code>Number</code> objects).
174      *
175      * @param values the values (in any order).
176      * @param start the start index.
177      * @param end the end index.
178      *
179      * @return The median.
180      */

181     public static double calculateMedian(List JavaDoc values, int start, int end) {
182         return calculateMedian(values, start, end, true);
183     }
184
185     /**
186      * Calculates the median for a sublist within a list of values
187      * (<code>Number</code> objects). The entire list will be sorted if the
188      * <code>ascending</code< argument is <code>false</code>.
189      *
190      * @param values the values.
191      * @param start the start index.
192      * @param end the end index.
193      * @param copyAndSort a flag that that controls whether the list of values
194      * is copied and sorted.
195      *
196      * @return The median.
197      */

198     public static double calculateMedian(List JavaDoc values, int start, int end,
199                                          boolean copyAndSort) {
200         
201         double result = Double.NaN;
202         if (copyAndSort) {
203             List JavaDoc working = new ArrayList JavaDoc(end - start + 1);
204             for (int i = start; i <= end; i++) {
205                 working.add(values.get(i));
206             }
207             Collections.sort(working);
208             result = calculateMedian(working, false);
209         }
210         else {
211             int count = end - start + 1;
212             if (count > 0) {
213                 if (count % 2 == 1) {
214                     if (count > 1) {
215                         Number JavaDoc value
216                             = (Number JavaDoc) values.get(start + (count - 1) / 2);
217                         result = value.doubleValue();
218                     }
219                     else {
220                         Number JavaDoc value = (Number JavaDoc) values.get(start);
221                         result = value.doubleValue();
222                     }
223                 }
224                 else {
225                     Number JavaDoc value1 = (Number JavaDoc) values.get(start + count / 2 - 1);
226                     Number JavaDoc value2 = (Number JavaDoc) values.get(start + count / 2);
227                     result
228                         = (value1.doubleValue() + value2.doubleValue()) / 2.0;
229                 }
230             }
231         }
232         return result;
233         
234     }
235     
236     /**
237      * Returns the standard deviation of a set of numbers.
238      *
239      * @param data the data.
240      *
241      * @return The standard deviation of a set of numbers.
242      */

243     public static double getStdDev(Number JavaDoc[] data) {
244         double avg = calculateMean(data);
245         double sum = 0.0;
246
247         for (int counter = 0; counter < data.length; counter++) {
248             double diff = data[counter].doubleValue() - avg;
249             sum = sum + diff * diff;
250         }
251         return Math.sqrt(sum / (data.length - 1));
252     }
253
254     /**
255      * Fits a straight line to a set of (x, y) data, returning the slope and
256      * intercept.
257      *
258      * @param xData the x-data.
259      * @param yData the y-data.
260      *
261      * @return A double array with the intercept in [0] and the slope in [1].
262      */

263     public static double[] getLinearFit(Number JavaDoc[] xData, Number JavaDoc[] yData) {
264
265         // check arguments...
266
if (xData.length != yData.length) {
267             throw new IllegalArgumentException JavaDoc(
268                 "Statistics.getLinearFit(): array lengths must be equal.");
269         }
270
271         double[] result = new double[2];
272         // slope
273
result[1] = getSlope(xData, yData);
274         // intercept
275
result[0] = calculateMean(yData) - result[1] * calculateMean(xData);
276
277         return result;
278
279     }
280
281     /**
282      * Finds the slope of a regression line using least squares.
283      *
284      * @param xData an array of Numbers (the x values).
285      * @param yData an array of Numbers (the y values).
286      *
287      * @return The slope.
288      */

289     public static double getSlope(Number JavaDoc[] xData, Number JavaDoc[] yData) {
290
291         // check arguments...
292
if (xData.length != yData.length) {
293             throw new IllegalArgumentException JavaDoc("Array lengths must be equal.");
294         }
295
296         // ********* stat function for linear slope ********
297
// y = a + bx
298
// a = ybar - b * xbar
299
// sum(x * y) - (sum (x) * sum(y)) / n
300
// b = ------------------------------------
301
// sum (x^2) - (sum(x)^2 / n
302
// *************************************************
303

304         // sum of x, x^2, x * y, y
305
double sx = 0.0, sxx = 0.0, sxy = 0.0, sy = 0.0;
306         int counter;
307         for (counter = 0; counter < xData.length; counter++) {
308             sx = sx + xData[counter].doubleValue();
309             sxx = sxx + Math.pow(xData[counter].doubleValue(), 2);
310             sxy = sxy + yData[counter].doubleValue()
311                       * xData[counter].doubleValue();
312             sy = sy + yData[counter].doubleValue();
313         }
314         return (sxy - (sx * sy) / counter) / (sxx - (sx * sx) / counter);
315
316     }
317
318     /**
319      * Calculates the correlation between two datasets. Both arrays should
320      * contain the same number of items. Null values are treated as zero.
321      * <P>
322      * Information about the correlation calculation was obtained from:
323      *
324      * http://trochim.human.cornell.edu/kb/statcorr.htm
325      *
326      * @param data1 the first dataset.
327      * @param data2 the second dataset.
328      *
329      * @return The correlation.
330      */

331     public static double getCorrelation(Number JavaDoc[] data1, Number JavaDoc[] data2) {
332         if (data1 == null) {
333             throw new IllegalArgumentException JavaDoc("Null 'data1' argument.");
334         }
335         if (data2 == null) {
336             throw new IllegalArgumentException JavaDoc("Null 'data2' argument.");
337         }
338         if (data1.length != data2.length) {
339             throw new IllegalArgumentException JavaDoc(
340                 "'data1' and 'data2' arrays must have same length."
341             );
342         }
343         int n = data1.length;
344         double sumX = 0.0;
345         double sumY = 0.0;
346         double sumX2 = 0.0;
347         double sumY2 = 0.0;
348         double sumXY = 0.0;
349         for (int i = 0; i < n; i++) {
350             double x = 0.0;
351             if (data1[i] != null) {
352                 x = data1[i].doubleValue();
353             }
354             double y = 0.0;
355             if (data2[i] != null) {
356                 y = data2[i].doubleValue();
357             }
358             sumX = sumX + x;
359             sumY = sumY + y;
360             sumXY = sumXY + (x * y);
361             sumX2 = sumX2 + (x * x);
362             sumY2 = sumY2 + (y * y);
363         }
364         return (n * sumXY - sumX * sumY) / Math.pow((n * sumX2 - sumX * sumX)
365                 * (n * sumY2 - sumY * sumY), 0.5);
366     }
367
368     /**
369      * Returns a data set for a moving average on the data set passed in.
370      *
371      * @param xData an array of the x data.
372      * @param yData an array of the y data.
373      * @param period the number of data points to average
374      *
375      * @return A double[][] the length of the data set in the first dimension,
376      * with two doubles for x and y in the second dimension
377      */

378     public static double[][] getMovingAverage(Number JavaDoc[] xData,
379                                               Number JavaDoc[] yData,
380                                               int period) {
381
382         // check arguments...
383
if (xData.length != yData.length) {
384             throw new IllegalArgumentException JavaDoc("Array lengths must be equal.");
385         }
386
387         if (period > xData.length) {
388             throw new IllegalArgumentException JavaDoc(
389                 "Period can't be longer than dataset."
390             );
391         }
392
393         double[][] result = new double[xData.length - period][2];
394         for (int i = 0; i < result.length; i++) {
395             result[i][0] = xData[i + period].doubleValue();
396             // holds the moving average sum
397
double sum = 0.0;
398             for (int j = 0; j < period; j++) {
399                 sum += yData[i + j].doubleValue();
400             }
401             sum = sum / period;
402             result[i][1] = sum;
403         }
404         return result;
405
406     }
407
408 }
409
Popular Tags