001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
006     *
007     * Project Info:  http://www.jfree.org/jfreechart/index.html
008     *
009     * This library is free software; you can redistribute it and/or modify it 
010     * under the terms of the GNU Lesser General Public License as published by 
011     * the Free Software Foundation; either version 2.1 of the License, or 
012     * (at your option) any later version.
013     *
014     * This library is distributed in the hope that it will be useful, but 
015     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
016     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
017     * License for more details.
018     *
019     * You should have received a copy of the GNU Lesser General Public
020     * License along with this library; if not, write to the Free Software
021     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
022     * USA.  
023     *
024     * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
025     * in the United States and other countries.]
026     *
027     * ---------------
028     * Regression.java
029     * ---------------
030     * (C) Copyright 2002-2005, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * $Id: Regression.java,v 1.3.2.1 2005/10/25 21:34:46 mungady Exp $
036     *
037     * Changes
038     * -------
039     * 30-Sep-2002 : Version 1 (DG);
040     * 18-Aug-2003 : Added 'abstract' (DG);
041     * 15-Jul-2004 : Switched getX() with getXValue() and getY() with 
042     *               getYValue() (DG);
043     *
044     */
045    
046    package org.jfree.data.statistics;
047    
048    import org.jfree.data.xy.XYDataset;
049    
050    /**
051     * A utility class for fitting regression curves to data.
052     */
053    public abstract class Regression {
054    
055        /**
056         * Returns the parameters 'a' and 'b' for an equation y = a + bx, fitted to
057         * the data using ordinary least squares regression.  The result is 
058         * returned as a double[], where result[0] --> a, and result[1] --> b.
059         *
060         * @param data  the data.
061         *
062         * @return The parameters.
063         */
064        public static double[] getOLSRegression(double[][] data) {
065    
066            int n = data.length;
067            if (n < 2) {
068                throw new IllegalArgumentException("Not enough data.");
069            }
070    
071            double sumX = 0;
072            double sumY = 0;
073            double sumXX = 0;
074            double sumXY = 0;
075            for (int i = 0; i < n; i++) {
076                double x = data[i][0];
077                double y = data[i][1];
078                sumX += x;
079                sumY += y;
080                double xx = x * x;
081                sumXX += xx;
082                double xy = x * y;
083                sumXY += xy;
084            }
085            double sxx = sumXX - (sumX * sumX) / n;
086            double sxy = sumXY - (sumX * sumY) / n;
087            double xbar = sumX / n;
088            double ybar = sumY / n;
089    
090            double[] result = new double[2];
091            result[1] = sxy / sxx;
092            result[0] = ybar - result[1] * xbar;
093    
094            return result;
095    
096        }
097    
098        /**
099         * Returns the parameters 'a' and 'b' for an equation y = a + bx, fitted to 
100         * the data using ordinary least squares regression. The result is returned 
101         * as a double[], where result[0] --> a, and result[1] --> b.
102         *
103         * @param data  the data.
104         * @param series  the series (zero-based index).
105         *
106         * @return The parameters.
107         */
108        public static double[] getOLSRegression(XYDataset data, int series) {
109    
110            int n = data.getItemCount(series);
111            if (n < 2) {
112                throw new IllegalArgumentException("Not enough data.");
113            }
114    
115            double sumX = 0;
116            double sumY = 0;
117            double sumXX = 0;
118            double sumXY = 0;
119            for (int i = 0; i < n; i++) {
120                double x = data.getXValue(series, i);
121                double y = data.getYValue(series, i);
122                sumX += x;
123                sumY += y;
124                double xx = x * x;
125                sumXX += xx;
126                double xy = x * y;
127                sumXY += xy;
128            }
129            double sxx = sumXX - (sumX * sumX) / n;
130            double sxy = sumXY - (sumX * sumY) / n;
131            double xbar = sumX / n;
132            double ybar = sumY / n;
133    
134            double[] result = new double[2];
135            result[1] = sxy / sxx;
136            result[0] = ybar - result[1] * xbar;
137    
138            return result;
139    
140        }
141    
142        /**
143         * Returns the parameters 'a' and 'b' for an equation y = ax^b, fitted to 
144         * the data using a power regression equation.  The result is returned as 
145         * an array, where double[0] --> a, and double[1] --> b.
146         *
147         * @param data  the data.
148         *
149         * @return The parameters.
150         */
151        public static double[] getPowerRegression(double[][] data) {
152    
153            int n = data.length;
154            if (n < 2) {
155                throw new IllegalArgumentException("Not enough data.");
156            }
157    
158            double sumX = 0;
159            double sumY = 0;
160            double sumXX = 0;
161            double sumXY = 0;
162            for (int i = 0; i < n; i++) {
163                double x = Math.log(data[i][0]);
164                double y = Math.log(data[i][1]);
165                sumX += x;
166                sumY += y;
167                double xx = x * x;
168                sumXX += xx;
169                double xy = x * y;
170                sumXY += xy;
171            }
172            double sxx = sumXX - (sumX * sumX) / n;
173            double sxy = sumXY - (sumX * sumY) / n;
174            double xbar = sumX / n;
175            double ybar = sumY / n;
176    
177            double[] result = new double[2];
178            result[1] = sxy / sxx;
179            result[0] = Math.pow(Math.exp(1.0), ybar - result[1] * xbar);
180    
181            return result;
182    
183        }
184    
185        /**
186         * Returns the parameters 'a' and 'b' for an equation y = ax^b, fitted to 
187         * the data using a power regression equation.  The result is returned as 
188         * an array, where double[0] --> a, and double[1] --> b.
189         *
190         * @param data  the data.
191         * @param series  the series to fit the regression line against.
192         *
193         * @return The parameters.
194         */
195        public static double[] getPowerRegression(XYDataset data, int series) {
196    
197            int n = data.getItemCount(series);
198            if (n < 2) {
199                throw new IllegalArgumentException("Not enough data.");
200            }
201    
202            double sumX = 0;
203            double sumY = 0;
204            double sumXX = 0;
205            double sumXY = 0;
206            for (int i = 0; i < n; i++) {
207                double x = Math.log(data.getXValue(series, i));
208                double y = Math.log(data.getYValue(series, i));
209                sumX += x;
210                sumY += y;
211                double xx = x * x;
212                sumXX += xx;
213                double xy = x * y;
214                sumXY += xy;
215            }
216            double sxx = sumXX - (sumX * sumX) / n;
217            double sxy = sumXY - (sumX * sumY) / n;
218            double xbar = sumX / n;
219            double ybar = sumY / n;
220    
221            double[] result = new double[2];
222            result[1] = sxy / sxx;
223            result[0] = Math.pow(Math.exp(1.0), ybar - result[1] * xbar);
224    
225            return result;
226    
227        }
228    
229    }