//
// 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 net.sourceforge.openforecast.DataSet;
/**
* A simple exponential smoothing forecast model is a very popular model
* used to produce a smoothed Time Series. Whereas in simple Moving Average
* models the past observations are weighted equally, Exponential Smoothing
* assigns exponentially decreasing weights as the observations get older.
*
* In other words, recent observations are given relatively more weight
* in forecasting than the older observations.
*
*
In the case of moving averages, the weights assigned to the
* observations are the same and are equal to 1/N. In
* simple exponential smoothing, however, a "smoothing parameter" - or
* "smoothing constant" - is used to determine the weights assigned to the
* observations.
*
*
This simple exponential smoothing model begins by setting the forecast
* for the second period equal to the observation of the first period. Note
* that there are ways of initializing the model. As of the time of writing,
* these alternatives are not available in this implementation. Future
* implementations of this model may offer these options.
*
*
Choosing a smoothing constant
* The smoothing constant must be a value in the range 0.0-1.0. But, what
* is the "best" value to use for the smoothing constant? This depends on the
* data series being modeled. The speed at which the older responses are
* dampened (smoothed) is a function of the value of the smoothing constant.
* When this smoothing constant is close to 1.0, dampening is quick - more
* weight is given to recent observations - and when it is close to 0.0,
* dampening is slow - and relatively less weight is given to recent
* observations.
*
*
The best value for the smoothing constant is the one that results in the
* smallest mean of the squared errors (or other similar accuracy indicator).
*
*
Note on alternate formulations
* This class supports two approaches to forecasting using Simple
* Exponential Smoothing. The first approach - and the default approach - is
* to use the formulation according to Hunter. Hunter's formulation uses the
* observed and forecast values from the previous period to come up with a
* forecast for the current period.
*
*
An alternative formulation is also supported - that proposed by Roberts.
* The formulation according to Roberts uses the observed value from the
* current period and the forecast value from the previous period to come up
* with a forecast for the current period.
*
*
By default, the formulation according to Hunter is used. To override
* this, use the {@link #SimpleExponentialSmoothingModel three argument
* constructor} and specify {@link #ROBERTS} as the third argument.
* @author Steven R. Gould
* @since 0.4
* @see Engineering Statistics Handbook, 6.4.3.1 Simple Expnential Smoothing
*/
public class SimpleExponentialSmoothingModel extends AbstractTimeBasedModel
{
/**
* The default value of the tolerance permitted in the estimates of the
* smoothing constants in the {@link #getBestFitModel} methods.
*/
private static double DEFAULT_SMOOTHING_CONSTANT_TOLERANCE = 0.001;
/**
* Used in the {@link #SimpleExponentialSmoothingModel three argument
* constructor} to specify that Hunter's formula is to be used for
* calculating forecast values. The formulation according to Hunter uses
* the observed and forecast values from the previous period to come up
* with a forecast for the current period.
*/
public static final int HUNTER = 1;
/**
* Used in the {@link #SimpleExponentialSmoothingModel three argument
* constructor} to specify that Robert's formula is to be used for
* calculating forecast values. The formulation according to Roberts uses
* the observed value from the current period and the forecast value from
* the previous period to come up with a forecast for the current period.
*/
public static final int ROBERTS = 2;
/**
* The smoothing constant, alpha, used in this exponential smoothing model.
*/
private double alpha;
/**
* Stores the approach to forecasting to be used in this instance of the
* Simple Exponential Smoothing model.
*/
private int approach;
/**
* Factory method that returns a "best fit" simple exponential smoothing
* model for the given data set. This, like the overloaded
* {@link #getBestFitModel(DataSet,double)}, attempts to derive a
* "good" - hopefully near optimal - value for the alpha smoothing
* constant.
* @param dataSet the observations for which a "best fit" simple
* exponential smoothing model is required.
* @return a best fit simple exponential smoothing model for the given
* data set.
* @see #getBestFitModel(DataSet,double)
*/
public static SimpleExponentialSmoothingModel
getBestFitModel( DataSet dataSet )
{
return getBestFitModel( dataSet,
DEFAULT_SMOOTHING_CONSTANT_TOLERANCE );
}
/**
* Factory method that returns a best fit simple exponential smoothing
* model for the given data set. This, like the overloaded
* {@link #getBestFitModel(DataSet)}, attempts to derive a "good" -
* hopefully near optimal - value for the alpha smoothing constant.
*
*
To determine which model is "best", this method currently uses only
* the Mean Squared Error (MSE). Future versions may use other measures in
* addition to the MSE. However, the resulting "best fit" model - and the
* associated value of alpha - is expected to be very similar either way.
*
*
Note that the approach used to calculate the best smoothing
* constant, alpha, may end up choosing values near a local
* optimum. In other words, there may be other values for alpha
* and that result in a model with the same, or even better MSE.
* @param dataSet the observations for which a "best fit" simple
* exponential smoothing model is required.
* @param alphaTolerance the required precision/accuracy - or tolerance
* of error - required in the estimate of the alpha smoothing constant.
* @return a best fit simple exponential smoothing model for the given
* data set.
*/
public static SimpleExponentialSmoothingModel
getBestFitModel( DataSet dataSet, double alphaTolerance )
{
SimpleExponentialSmoothingModel model1
= new SimpleExponentialSmoothingModel( 0.0 );
SimpleExponentialSmoothingModel model2
= new SimpleExponentialSmoothingModel( 0.5 );
SimpleExponentialSmoothingModel model3
= new SimpleExponentialSmoothingModel( 1.0 );
return findBestFit( dataSet, model1, model2, model3, TOLERANCE );
}
/**
* Performs a somewhat intelligent search for the best values for the
* smoothing constant, alpha, for the given data set. For the given data
* set and models with a small, medium and large value of the alpha
* smoothing constant, returns the best fit model where the value of the
* alpha smoothing constant is within the given tolerances.
*
*
Note that the descriptions of the parameters below include a
* discussion of valid values. However, since this is a private method and
* to help improve performance, we don't provide any validation of these
* parameters. Using invalid values may lead to unexpected results.
* @param dataSet the data set for which a best fit model is required.
* @param modelMin the pre-initialized best fit model with the smallest
* value of the alpha smoothing constant found so far.
* @param modelMid the pre-initialized best fit model with the value of
* the alpha smoothing constant between that of modelMin and modelMax.
* @param modelMax the pre-initialized best fit model with the largest
* value of the alpha smoothing constant found so far.
* @param alphaTolerance the tolerance within which the alpha value is
* required. Must be considerably less than 1.0. However, note that the
* smaller this value the longer it will take to diverge on a best fit
* model.
*/
private static SimpleExponentialSmoothingModel findBestFit(
DataSet dataSet,
SimpleExponentialSmoothingModel modelMin,
SimpleExponentialSmoothingModel modelMid,
SimpleExponentialSmoothingModel modelMax,
double alphaTolerance)
{
double alphaMin = modelMin.getAlpha();
double alphaMid = modelMid.getAlpha();
double alphaMax = modelMax.getAlpha();
// If we're not making much ground, then we're done
if (Math.abs(alphaMid-alphaMin) 1.0 )
throw new IllegalArgumentException("SimpleExponentialSmoothingModel: Invalid smoothing constant, " + alpha + " - must be in the range 0.0-1.0.");
this.alpha = alpha;
this.approach = approach;
}
/**
* Constructs a new exponential smoothing forecasting model, using the
* given name as the independent variable and the specified smoothing
* constant.
* @param independentVariable the name of the independent variable - or
* time variable - to use in this model.
* @param alpha the smoothing constant to use for this exponential
* smoothing model. Must be a value in the range 0.0-1.0.
* @param approach determines which approach to use for the forecasting.
* This must be either {@link #HUNTER} - the default - or {@link #ROBERTS}.
* @throws IllegalArgumentException if the value of the smoothing constant
* is invalid - outside the range 0.0-1.0.
* @deprecated As of 0.4, replaced by {@link #SimpleExponentialSmoothingModel(double,int)}.
*/
public SimpleExponentialSmoothingModel( String independentVariable,
double alpha,
int approach )
{
super(independentVariable);
if ( alpha < 0.0 || alpha > 1.0 )
throw new IllegalArgumentException("SimpleExponentialSmoothingModel: Invalid smoothing constant, " + alpha + " - must be in the range 0.0-1.0.");
this.alpha = alpha;
this.approach = approach;
}
/**
* Returns the forecast value of the dependent variable for the given
* value of the independent time variable using a single exponential
* smoothing model. The model used here follows the formulation of
* Hunter that combines the observation and forecast values from the
* previous period.
* @param timeValue the value of the time variable for which a forecast
* value is required.
* @return the forecast value of the dependent variable for the given
* time.
* @throws IllegalArgumentException if there is insufficient historical
* data - observations passed to init - to generate a forecast for the
* given time value.
*/
protected double forecast( double timeValue )
throws IllegalArgumentException
{
// As a starting point, we set the first forecast value to be the
// same as the first observed value
if ( timeValue-getMinimumTimeValue() < TOLERANCE )
return getObservedValue( timeValue );
double previousTime = timeValue - getTimeInterval();
double forecast;
try
{
if ( approach == ROBERTS )
forecast
= alpha*getObservedValue(timeValue)
+ (1.0-alpha)*getForecastValue(previousTime);
else // Default - Hunter's formula
forecast
= alpha*getObservedValue(previousTime)
+ (1.0-alpha)*getForecastValue(previousTime);
}
catch ( IllegalArgumentException iaex )
{
// For "future" forecasts, all we can do is use the forecast
// from the last period
if ( timeValue > getMaximumTimeValue()-TOLERANCE )
return getForecastValue( getMaximumTimeValue() );
throw iaex;
}
return forecast;
}
/**
* Returns the current number of periods used in this model. This is also
* the minimum number of periods required in order to produce a valid
* forecast. Strictly speaking, for simple exponential smoothing only one
* previous period is needed - though such a model would be of relatively
* little use. At least five to ten prior observations would be preferred.
* @return the minimum number of periods used in this model.
*/
protected int getNumberOfPeriods()
{
return 1;
}
/**
* Returns the number of predictors used by the underlying model.
* @return the number of predictors used by the underlying model.
* @since 0.5
*/
public int getNumberOfPredictors()
{
return 1;
}
/**
* Returns the value of the smoothing constant, alpha, used in this model.
* @return the value of the smoothing constant, alpha.
*/
public double getAlpha()
{
return alpha;
}
/**
* Returns a one or two word name of this type of forecasting model. Keep
* this short. A longer description should be implemented in the toString
* method.
* @return a string representation of the type of forecasting model
* implemented.
*/
public String getForecastType()
{
return "simple exponential smoothing";
}
/**
* This should be overridden to provide a textual description of the
* current forecasting model including, where possible, any derived
* parameters used.
* @return a string representation of the current forecast model, and its
* parameters.
*/
public String toString()
{
return "Simple exponential smoothing model (using "
+ (approach==ROBERTS?"Roberts":"Hunters")
+ " formula), with a smoothing constant of "
+ alpha + " and using an independent variable of "
+ getIndependentVariable();
}
}
// Local Variables:
// tab-width: 4
// End:
Ads help maintain this website.