//
// OpenForecast - open source, general-purpose forecasting package.
// Copyright (C) 2002-2011 Steven R. Gould
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
package net.sourceforge.openforecast.models;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Hashtable;
import java.util.Map;
import java.util.Set;
import net.sourceforge.openforecast.DataPoint;
import net.sourceforge.openforecast.DataSet;
/**
* Implements a multiple variable linear regression model using the variables
* named in the constructor as the independent variables, or the variables
* passed into one of the init methods. The cofficients of the regression, as
* well as the accuracy indicators are determined from the data set passed to
* init.
*
* Once initialized, this model can be applied to another data set using
* the forecast method to forecast values of the dependent variable based on
* values of the dependent variable (the one named in the constructor).
*
*
A multiple variable linear regression model essentially attempts to put
* a hyperplane through the data points. Mathematically, assuming the
* independent variables are xi and the dependent variable is y,
* then this hyperplane can be represented as:
*
y = a0 + a1*x1 + a2*x2 + a3*x3 + ...
* where the ai are the coefficients of the regression. The
* coefficient a0 is also referred to as the intercept. If all
* xi were zero (theoretically at least), it is the forecast value
* of the dependentVariable, y.
* @author Steven R. Gould
* @since 0.2
*/
public class MultipleLinearRegressionModel extends AbstractForecastingModel
{
/**
* The intercept for the linear regression model. Initialized following a
* call to init.
*/
private double intercept = 0.0;
/**
* An mapping of variable names to coefficients for this multiple variable
* linear regression model. These are initialized following a call to init.
*/
private Hashtable coefficient;
/**
* A default constructor that constructs a new multiple variable Linear
* regression model. When this constructor is used, it is assumed that all
* independent variables in the DataSet or list of coefficients passed to
* init are to be used in the model. To narrow down and explicitly define
* what independent variables to use in the model, use the alternate form
* of the constructor.
*
* For a valid model to be constructed, you should call either
* implementation of init.
* @see #init(DataSet)
* @see #init(double,Hashtable)
*/
public MultipleLinearRegressionModel()
{
coefficient = null;
}
/**
* Constructs a new multiple variable linear regression model, using the
* given array of names as the independent variables to use. For a valid
* model to be constructed, you should call init and pass in a data set
* containing a series of data points involving the given independent
* variables.
* @param independentVariable an array of names of the independent
* variables to use in this model.
* @see #init(DataSet)
* @see #init(double,Hashtable)
*/
public MultipleLinearRegressionModel( String[] independentVariable )
{
setIndependentVariables( independentVariable );
}
/**
* Initializes the coefficients to use for this regression model. The
* coefficients are derived so as to give the best fit hyperplane for the
* given data set.
*
*
Additionally, the accuracy indicators are calculated based on this
* data set.
* @param dataSet the set of observations to use to derive the regression
* coefficients for this model.
*/
public void init( DataSet dataSet )
{
String varNames[] = dataSet.getIndependentVariables();
// If no coefficients have been defined for this model,
// use all that exist in this data set
if ( coefficient == null )
setIndependentVariables( varNames );
int n = varNames.length;
double a[][] = new double[n+1][n+2];
// Iterate through dataSet
Iterator it = dataSet.iterator();
while ( it.hasNext() )
{
// Get next data point
DataPoint dp = it.next();
// For each row in the matrix, a
for ( int row=0; row 0 )
{
// Get value of independent variable, col
String colVarName = varNames[col-1];
colMult = dp.getIndependentValue(colVarName);
}
a[row][col] += rowMult * colMult;
}
}
}
// Solve equations to derive coefficients
double coeff[] = Utils.GaussElimination( a );
// Assign coefficients to independent variables
intercept = coeff[0];
for ( int i=1; iIn addition to the coefficients, you must also specify the
* constant term - or the "intercept" - to use in the regression model.
*
* Note that since this method does not require a data set, it is
* not possible to calculate the values of the accuracy indicators.
* Therefore these are all set to their worse-case values.
* @param intercept the constant term - or the "intercept" - to use in
* the regression model.
* @param coefficients the coefficients to be assigned for use in this
* regression model.
* @throws ModelNotInitializedException if a coefficient does not exist
* in the given Hashtable of coefficients for one or more of the
* independent variables used when constructing this model.
* @throws ClassCastException if the "value" associated with one of the
* coefficients cannot be cast to a Number.
*/
public void init( double intercept, Hashtable coefficients )
{
// If no coefficients have been defined for this model,
// use all that exist in the list of coefficients
if ( coefficient == null )
{
// Iterate through the set of keys, building a String[]
Enumeration keysEnum = coefficients.keys();
String[] keys = new String[ coefficients.size() ];
int k = 0;
while ( keysEnum.hasMoreElements() )
keys[k++] = keysEnum.nextElement();
setIndependentVariables( keys );
}
this.intercept = intercept;
// Iterate through the variable names in this.coefficient
Iterator it = coefficient.keySet().iterator();
while ( it.hasNext() )
{
// Get variable name
String name = it.next();
// Look up variable in coefficients Hashtable
double coeff = ((Number)coefficients.get(name)).doubleValue();
// Assign value back into this.coefficient
coefficient.put( name, new Double(coeff) );
}
// Indicate that the model has been initialized
initialized = true;
// Note that accuracy indicators by default are initialized to
// their worst possible values, so no need to update them here
}
/**
* Returns the intercept that will be used by the current model. This
* could be a user-defined value or internally calculated depending on
* which of the init methods was used to initialize the model.
* @return the intercept that will be used by this model.
* @throws ModelNotInitializedException if this method is called before
* the model has been initialized with a call to init.
*/
public double getIntercept()
{
if ( !initialized )
throw new ModelNotInitializedException();
return intercept;
}
/**
* Returns a Hashtable containing the coefficients that will be used by
* the current model. These could be user-defined coefficients or
* internally calculated coefficients depending on which of the init
* methods were used to initialize the model.
*
* Note that modifying the coefficients in the Hashtable returned from
* this method will not modify the coefficients used by the model. If you
* want to modify the coefficients used in the model, then use the
* {@link #init(double,Hashtable)} method to re-initialize the model.
* @return a Hashtable containing the coefficients that will be used by
* this model.
* @throws ModelNotInitializedException if this method is called before
* the model has been initialized with a call to init.
*/
public Hashtable getCoefficients()
{
if ( !initialized )
throw new ModelNotInitializedException();
return new Hashtable( coefficient );
}
/**
* Returns the number of predictors used by the underlying model.
* @return the number of predictors used by the underlying model.
*/
public int getNumberOfPredictors()
{
return coefficient.size();
}
/**
* Using the current model parameters (initialized in init), apply the
* forecast model to the given data point. The data point must have valid
* values for the independent variables. Upon return, the value of the
* dependent variable will be updated with the forecast value computed for
* that data point.
* @param dataPoint the data point for which a forecast value (for the
* dependent variable) is required.
* @return the forecast value of the dependent variable for the given data
* point.
* @throws ModelNotInitializedException if forecast is called before the
* model has been initialized with a call to init.
*/
public double forecast( DataPoint dataPoint )
{
if ( !initialized )
throw new ModelNotInitializedException();
double forecastValue = intercept;
Iterator< Map.Entry > it = coefficient.entrySet().iterator();
while ( it.hasNext() )
{
Map.Entry entry = it.next();
// Get value of independent variable
double x = dataPoint.getIndependentValue( (String)entry.getKey() );
// Get coefficient for this variable
double coeff = ((Double)entry.getValue()).doubleValue();
forecastValue += coeff * x;
}
dataPoint.setDependentValue( forecastValue );
return forecastValue;
}
/**
* A helper function that initializes the set of independent variables used
* in this model to the given array of independent variable names.
* @param independentVariable an array of independent variables to use in
* this MultipleLinearRegressionModel.
*/
private void setIndependentVariables(String[] independentVariable)
{
// Create a new hashtable of just the right size
coefficient = new Hashtable( independentVariable.length );
// Add each independent variable with an initial coefficient of 0.0
for ( int v=0; v TOLERANCE )
desc += "+" + coeff + "*" + entry.getKey();
// else coeff == 0.0
}
return desc;
}
}
// Local variables:
// tab-width: 4
// End:
Ads help maintain this website.