001    /* ===========================================================
002     * JFreeChart : a free chart library for the Java(tm) platform
003     * ===========================================================
004     *
005     * (C) Copyright 2000-2008, 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-2008, by Object Refinery Limited.
031     *
032     * Original Author:  David Gilbert (for Object Refinery Limited);
033     * Contributor(s):   -;
034     *
035     * Changes
036     * -------
037     * 30-Sep-2002 : Version 1 (DG);
038     * 18-Aug-2003 : Added 'abstract' (DG);
039     * 15-Jul-2004 : Switched getX() with getXValue() and getY() with
040     *               getYValue() (DG);
041     *
042     */
043    
044    package org.jfree.data.statistics;
045    
046    import org.jfree.data.xy.XYDataset;
047    
048    /**
049     * A utility class for fitting regression curves to data.
050     */
051    public abstract class Regression {
052    
053        /**
054         * Returns the parameters 'a' and 'b' for an equation y = a + bx, fitted to
055         * the data using ordinary least squares regression.  The result is
056         * returned as a double[], where result[0] --> a, and result[1] --> b.
057         *
058         * @param data  the data.
059         *
060         * @return The parameters.
061         */
062        public static double[] getOLSRegression(double[][] data) {
063    
064            int n = data.length;
065            if (n < 2) {
066                throw new IllegalArgumentException("Not enough data.");
067            }
068    
069            double sumX = 0;
070            double sumY = 0;
071            double sumXX = 0;
072            double sumXY = 0;
073            for (int i = 0; i < n; i++) {
074                double x = data[i][0];
075                double y = data[i][1];
076                sumX += x;
077                sumY += y;
078                double xx = x * x;
079                sumXX += xx;
080                double xy = x * y;
081                sumXY += xy;
082            }
083            double sxx = sumXX - (sumX * sumX) / n;
084            double sxy = sumXY - (sumX * sumY) / n;
085            double xbar = sumX / n;
086            double ybar = sumY / n;
087    
088            double[] result = new double[2];
089            result[1] = sxy / sxx;
090            result[0] = ybar - result[1] * xbar;
091    
092            return result;
093    
094        }
095    
096        /**
097         * Returns the parameters 'a' and 'b' for an equation y = a + bx, fitted to
098         * the data using ordinary least squares regression. The result is returned
099         * as a double[], where result[0] --> a, and result[1] --> b.
100         *
101         * @param data  the data.
102         * @param series  the series (zero-based index).
103         *
104         * @return The parameters.
105         */
106        public static double[] getOLSRegression(XYDataset data, int series) {
107    
108            int n = data.getItemCount(series);
109            if (n < 2) {
110                throw new IllegalArgumentException("Not enough data.");
111            }
112    
113            double sumX = 0;
114            double sumY = 0;
115            double sumXX = 0;
116            double sumXY = 0;
117            for (int i = 0; i < n; i++) {
118                double x = data.getXValue(series, i);
119                double y = data.getYValue(series, i);
120                sumX += x;
121                sumY += y;
122                double xx = x * x;
123                sumXX += xx;
124                double xy = x * y;
125                sumXY += xy;
126            }
127            double sxx = sumXX - (sumX * sumX) / n;
128            double sxy = sumXY - (sumX * sumY) / n;
129            double xbar = sumX / n;
130            double ybar = sumY / n;
131    
132            double[] result = new double[2];
133            result[1] = sxy / sxx;
134            result[0] = ybar - result[1] * xbar;
135    
136            return result;
137    
138        }
139    
140        /**
141         * Returns the parameters 'a' and 'b' for an equation y = ax^b, fitted to
142         * the data using a power regression equation.  The result is returned as
143         * an array, where double[0] --> a, and double[1] --> b.
144         *
145         * @param data  the data.
146         *
147         * @return The parameters.
148         */
149        public static double[] getPowerRegression(double[][] data) {
150    
151            int n = data.length;
152            if (n < 2) {
153                throw new IllegalArgumentException("Not enough data.");
154            }
155    
156            double sumX = 0;
157            double sumY = 0;
158            double sumXX = 0;
159            double sumXY = 0;
160            for (int i = 0; i < n; i++) {
161                double x = Math.log(data[i][0]);
162                double y = Math.log(data[i][1]);
163                sumX += x;
164                sumY += y;
165                double xx = x * x;
166                sumXX += xx;
167                double xy = x * y;
168                sumXY += xy;
169            }
170            double sxx = sumXX - (sumX * sumX) / n;
171            double sxy = sumXY - (sumX * sumY) / n;
172            double xbar = sumX / n;
173            double ybar = sumY / n;
174    
175            double[] result = new double[2];
176            result[1] = sxy / sxx;
177            result[0] = Math.pow(Math.exp(1.0), ybar - result[1] * xbar);
178    
179            return result;
180    
181        }
182    
183        /**
184         * Returns the parameters 'a' and 'b' for an equation y = ax^b, fitted to
185         * the data using a power regression equation.  The result is returned as
186         * an array, where double[0] --> a, and double[1] --> b.
187         *
188         * @param data  the data.
189         * @param series  the series to fit the regression line against.
190         *
191         * @return The parameters.
192         */
193        public static double[] getPowerRegression(XYDataset data, int series) {
194    
195            int n = data.getItemCount(series);
196            if (n < 2) {
197                throw new IllegalArgumentException("Not enough data.");
198            }
199    
200            double sumX = 0;
201            double sumY = 0;
202            double sumXX = 0;
203            double sumXY = 0;
204            for (int i = 0; i < n; i++) {
205                double x = Math.log(data.getXValue(series, i));
206                double y = Math.log(data.getYValue(series, i));
207                sumX += x;
208                sumY += y;
209                double xx = x * x;
210                sumXX += xx;
211                double xy = x * y;
212                sumXY += xy;
213            }
214            double sxx = sumXX - (sumX * sumX) / n;
215            double sxy = sumXY - (sumX * sumY) / n;
216            double xbar = sumX / n;
217            double ybar = sumY / n;
218    
219            double[] result = new double[2];
220            result[1] = sxy / sxx;
221            result[0] = Math.pow(Math.exp(1.0), ybar - result[1] * xbar);
222    
223            return result;
224    
225        }
226    
227    }