//
// OpenForecast - open source, general-purpose forecasting package.
// Copyright (C) 2004-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.Iterator;
import net.sourceforge.openforecast.DataPoint;
import net.sourceforge.openforecast.DataSet;
import net.sourceforge.openforecast.Observation;
/**
* Triple exponential smoothing - also known as the Winters method - is a
* refinement of the popular double exponential smoothing model but adds
* another component which takes into account any seasonality - or periodicity
* - in the data.
*
* Simple exponential smoothing models work best with data where there are
* no trend or seasonality components to the data. When the data exhibits
* either an increasing or decreasing trend over time, simple exponential
* smoothing forecasts tend to lag behind observations. Double exponential
* smoothing is designed to address this type of data series by taking into
* account any trend in the data. However, neither of these exponential
* smoothing models address any seasonality in the data.
*
*
For better exponentially smoothed forecasts of data where there is
* expected or known to be seasonal variation in the data, use triple
* exponential smoothing.
*
*
As with simple exponential smoothing, in triple exponential smoothing
* models past observations are given exponentially smaller weights as the
* observations get older. In other words, recent observations are given
* relatively more weight in forecasting than the older observations. This is
* true for all terms involved - namely, the base level
* Lt, the trend Tt as well as
* the seasonality index st.
*
*
There are four equations associated with Triple Exponential Smoothing.
*
*
* Lt = a.(xt/st-c)+(1-a).(Lt-1+Tt-1)
* Tt = b.(Lt-Lt-1)+(1-b).Tt-1
* st = g.(xt/Lt)+(1-g).st-c
* ft,k = (Lt+k.Tt).st+k-c
*
*
* where:
*
* Lt is the estimate of the base value at time
* t. That is, the estimate for time t after
* eliminating the effects of seasonality and trend.
* a - representing alpha - is the first smoothing
* constant, used to smooth Lt.
* xt is the observed value at time t.
* st is the seasonal index at time t.
* c is the number of periods in the seasonal pattern. For
* example, c=4 for quarterly data, or c=12 for monthly data.
* Tt is the estimated trend at time t.
* b - representing beta - is the second smoothing
* constant, used to smooth the trend estimates.
* g - representing gamma - is the third smoothing constant,
* used to smooth the seasonality estimates.
* ft,k is the forecast at time the end of period
* t for the period t+k.
*
*
* There are a variety of different ways to come up with initial values for
* the triple exponential smoothing model. The approach implemented here uses
* the first two "years" (or complete cycles) of data to come up with initial
* values for Lt, Tt and
* st. Therefore, at least two complete cycles of data
* are required to initialize the model. For best results, more data is
* recommended - ideally a minimum of 4 or 5 complete cycles. This gives the
* model chance to better adapt to the data, instead of relying on getting
* - guessing - good estimates for the initial conditions.
*
*
Choosing values for the smoothing constants
* The smoothing constants a, b, and
* g each must be a value in the range 0.0-1.0. But, what are the
* "best" values to use for the smoothing constants? This depends on the data
* series being modeled.
*
*
In general, 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).
* The {@link #getBestFitModel} static methods can help with the selection of
* the best values for the smoothing constants, though the results obtained
* from these methods should always be validated. If any of the "best fit"
* smoothing constants turns out to be 1.0, you may want to be a little
* suspicious. This may be an indication that you really need to use more data
* to initialize the model.
* @author Steven R. Gould
* @since 0.4
* @see Engineering Statistics Handbook, 6.4.3.5 Triple Exponential Smoothing
*/
public class TripleExponentialSmoothingModel 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;
/**
* Minimum number of years of data required.
*/
private static int NUMBER_OF_YEARS = 2;
/**
* The overall smoothing constant, alpha, used in this exponential
* smoothing model.
*/
private double alpha;
/**
* The second smoothing constant, beta, used in this exponential
* smoothing model for trend smoothing.
*/
private double beta;
/**
* The third smoothing constant (gamma) used in this exponential smoothing
* model for the seasonal smoothing.
*/
private double gamma;
/**
* Stores the number of periods per year in this exponential smoothing
* model. Note that, in spite of the name, this does not limit the
* functionality of this model to seasonality within a year. It is quite
* possible that the "seasonality" - or periodicity - of interest is the
* variability by day within a week, or any other period.
*/
private int periodsPerYear = 0;
/**
* Stores the maximum observed time. Initialized in {@link #init}.
*/
private double maxObservedTime;
/**
* Provides a cache of calculated baseValues. The "base" represents an
* estimate of the underlying value of the data after accounting for
* - i.e. removing - the effects of trend and seasonality. Since these
* values are used very frequently when calculating forecast values, it
* is more efficient to cache the previously calculated base values for
* future use.
*/
private DataSet baseValues;
/**
* Provides a cache of calculated trendValues. Since these values are
* used very frequently when calculating forecast values, it is more
* efficient to cache the previously calculated trend values for future
* use.
*/
private DataSet trendValues;
/**
* Provides a cache of calculated seasonal indexes. Since these values
* are used very frequently when calculating forecast values, it is more
* efficient to cache the previously calculated seasonal index values
* for future use than have to recalculate them each time.
*/
private DataSet seasonalIndex;
/**
* Factory method that returns a "best fit" triple exponential smoothing
* model for the given data set. This, like the overloaded
* {@link #getBestFitModel(DataSet,double,double)}, attempts to derive
* "good" - hopefully near optimal - values for the alpha and beta
* smoothing constants.
* @param dataSet the observations for which a "best fit" triple
* exponential smoothing model is required.
* @return a best fit triple exponential smoothing model for the given
* data set.
* @see #getBestFitModel(DataSet,double,double)
*/
public static TripleExponentialSmoothingModel
getBestFitModel( DataSet dataSet )
{
return getBestFitModel( dataSet,
DEFAULT_SMOOTHING_CONSTANT_TOLERANCE,
DEFAULT_SMOOTHING_CONSTANT_TOLERANCE );
}
/**
* Factory method that returns a best fit triple exponential smoothing
* model for the given data set. This, like the overloaded
* {@link #getBestFitModel(DataSet)}, attempts to derive "good" -
* hopefully near optimal - values for the alpha and beta smoothing
* constants.
*
*
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 values of alpha and beta - is expected to be very similar
* either way.
*
*
Note that the approach used to calculate the best smoothing
* constants - alpha and beta - may end up choosing values near
* a local optimum. In other words, there may be other values for
* alpha and beta that result in an even better model.
* @param dataSet the observations for which a "best fit" triple
* exponential smoothing model is required.
* @param alphaTolerance the required precision/accuracy - or tolerance
* of error - required in the estimate of the alpha smoothing constant.
* @param betaTolerance the required precision/accuracy - or tolerance
* of error - required in the estimate of the beta smoothing constant.
* @return a best fit triple exponential smoothing model for the given
* data set.
*/
public static TripleExponentialSmoothingModel
getBestFitModel( DataSet dataSet,
double alphaTolerance, double betaTolerance )
{
// Check we have the minimum amount of data points
if ( dataSet.size() < NUMBER_OF_YEARS*dataSet.getPeriodsPerYear() )
throw new IllegalArgumentException("TripleExponentialSmoothing models require a minimum of a full two years of data in the data set.");
// Check alphaTolerance is in the expected range
if ( alphaTolerance < 0.0 || alphaTolerance > 0.5 )
throw new IllegalArgumentException("The value of alphaTolerance must be significantly less than 1.0, and no less than 0.0. Suggested value: "+DEFAULT_SMOOTHING_CONSTANT_TOLERANCE);
// Check betaTolerance is in the expected range
if ( betaTolerance < 0.0 || betaTolerance > 0.5 )
throw new IllegalArgumentException("The value of betaTolerance must be significantly less than 1.0, and no less than 0.0. Suggested value: "+DEFAULT_SMOOTHING_CONSTANT_TOLERANCE);
TripleExponentialSmoothingModel model1
= findBestBeta( dataSet, 0.0, 0.0, 1.0, betaTolerance );
TripleExponentialSmoothingModel model2
= findBestBeta( dataSet, 0.5, 0.0, 1.0, betaTolerance );
TripleExponentialSmoothingModel model3
= findBestBeta( dataSet, 1.0, 0.0, 1.0, betaTolerance );
// First rough estimate of alpha and beta to the nearest 0.1
TripleExponentialSmoothingModel bestModel
= findBest( dataSet, model1, model2, model3,
alphaTolerance, betaTolerance );
return bestModel;
}
/**
* Performs a non-linear - yet somewhat intelligent - search for the best
* values for the smoothing coefficients alpha and beta 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 and beta (trend) smoothing constants are 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.
* @param betaTolerance the tolerance within which the beta 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. This value can be the same as, greater than or less than the
* value of the alphaTolerance parameter. It makes no difference - at
* least to this code.
*/
private static TripleExponentialSmoothingModel findBest(
DataSet dataSet,
TripleExponentialSmoothingModel modelMin,
TripleExponentialSmoothingModel modelMid,
TripleExponentialSmoothingModel modelMax,
double alphaTolerance,
double betaTolerance)
{
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)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 alpha the (fixed) value of the alpha smoothing constant to use
* for the best fit model.
* @param betaMin the minimum value of the beta (trend) smoothing
* constant accepted in the resulting best fit model. Must be greater than
* (or equal to) 0.0 and less than betaMax.
* @param betaMax the maximum value of the beta (trend) smoothing
* constant accepted in the resulting best fit model. Must be greater than
* betaMin and less than (or equal to) 1.0.
* @param betaTolerance the tolerance within which the beta 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 TripleExponentialSmoothingModel findBestBeta(
DataSet dataSet, double alpha,
double betaMin, double betaMax,
double betaTolerance )
{
int stepsPerIteration = 10;
if ( betaMin < 0.0 )
betaMin = 0.0;
if ( betaMax > 1.0 )
betaMax = 1.0;
TripleExponentialSmoothingModel bestModel
= new TripleExponentialSmoothingModel( alpha, betaMin, 0.0 );
bestModel.init(dataSet);
double initialMSE = bestModel.getMSE();
boolean betaImproving = true;
double betaStep = (betaMax-betaMin)/stepsPerIteration;
double beta = betaMin + betaStep;
for ( ; beta<=betaMax || betaImproving; )
{
TripleExponentialSmoothingModel model
= new TripleExponentialSmoothingModel( alpha, beta, 0.0 );
model.init( dataSet );
if ( model.getMSE() < bestModel.getMSE() )
bestModel = model;
else
betaImproving = false;
beta += betaStep;
if ( beta > 1.0 )
betaImproving = false;
}
// If we're making progress, then try to refine the beta estimate
if ( bestModel.getMSE() < initialMSE
&& betaStep > betaTolerance )
{
// Can this be further refined - improving efficiency - by
// only searching in the range beta-betaStep/2 to
// beta+betaStep/2 ?
return findBestBeta( dataSet, bestModel.getAlpha(),
bestModel.getBeta()-betaStep,
bestModel.getBeta()+betaStep,
betaTolerance );
}
return bestModel;
}
/**
* Constructs a new triple exponential smoothing forecasting model, using
* the given smoothing constants - alpha, beta and gamma. For a valid
* model to be constructed, you should call init and pass in a data set
* containing a series of data points with the time variable initialized
* to identify the independent variable.
* @param alpha the smoothing constant to use for this exponential
* smoothing model. Must be a value in the range 0.0-1.0. Values above 0.5
* are uncommon - though they are still valid and are supported by this
* implementation.
* @param beta the second smoothing constant, beta to use in this model
* to smooth the trend. Must be a value in the range 0.0-1.0. Values above
* 0.5 are uncommon - though they are still valid and are supported by this
* implementation.
* @param gamma the third smoothing constant, gamma to use in this model
* to smooth the seasonality. Must be a value in the range 0.0-1.0.
* @throws IllegalArgumentException if the value of any of the smoothing
* constants are invalid - outside the range 0.0-1.0.
*/
public TripleExponentialSmoothingModel( double alpha,
double beta,
double gamma )
{
if ( alpha < 0.0 || alpha > 1.0 )
throw new IllegalArgumentException("TripleExponentialSmoothingModel: Invalid smoothing constant, " + alpha + " - must be in the range 0.0-1.0.");
if ( beta < 0.0 || beta > 1.0 )
throw new IllegalArgumentException("TripleExponentialSmoothingModel: Invalid smoothing constant, beta=" + beta + " - must be in the range 0.0-1.0.");
if ( gamma < 0.0 || gamma > 1.0 )
throw new IllegalArgumentException("TripleExponentialSmoothingModel: Invalid smoothing constant, gamma=" + gamma + " - must be in the range 0.0-1.0.");
baseValues = new DataSet();
trendValues = new DataSet();
seasonalIndex = new DataSet();
this.alpha = alpha;
this.beta = beta;
this.gamma = gamma;
}
/**
* Used to initialize the time based model. This method must be called
* before any other method in the class. Since the time based model does
* not derive any equation for forecasting, this method uses the input
* DataSet to calculate forecast values for all values of the independent
* time variable within the initial data set.
* @param dataSet a data set of observations that can be used to
* initialize the forecasting parameters of the forecasting model.
*/
public void init( DataSet dataSet )
{
initTimeVariable( dataSet );
String timeVariable = getTimeVariable();
if ( dataSet.getPeriodsPerYear() <= 1 )
throw new IllegalArgumentException("Data set passed to init in the triple exponential smoothing model does not contain seasonal data. Don't forget to call setPeriodsPerYear on the data set to set this.");
periodsPerYear = dataSet.getPeriodsPerYear();
// Check we have the minimum amount of data points
if ( dataSet.size() < NUMBER_OF_YEARS*periodsPerYear )
throw new IllegalArgumentException("TripleExponentialSmoothing models require a minimum of a full two years of data to initialize the model.");
// Calculate initial values for base and trend
initBaseAndTrendValues( dataSet );
// Initialize seasonal indices using data for all complete years
initSeasonalIndices( dataSet );
Iterator it = dataSet.iterator();
maxObservedTime = Double.NEGATIVE_INFINITY;
while ( it.hasNext() )
{
DataPoint dp = it.next();
if ( dp.getIndependentValue(timeVariable) > maxObservedTime )
maxObservedTime = dp.getIndependentValue(timeVariable);
}
super.init( dataSet );
}
/**
* Calculates (and caches) the initial base and trend values for the given
* DataSet. Note that there are a variety of ways to estimate initial
* values for both the base and the trend. The approach here averages the
* trend calculated from the first two complete "years" - or cycles - of
* data in the DataSet.
* @param dataSet the set of data points - observations - to use to
* initialize the base and trend values.
*/
private void initBaseAndTrendValues( DataSet dataSet )
{
String timeVariable = getTimeVariable();
double trend = 0.0;
Iterator it = dataSet.iterator();
for ( int p=0; p= periodsPerYear )
{
// This formula gets a little convoluted partly due to
// the fact that p is zero-based, and partly because
// of the generalized nature of the formula
dp.setDependentValue(year2Average
+ (p+1-periodsPerYear
-(periodsPerYear+1)/2.0)*trend);
//dp.setIndependentValue( timeVariable, time );
baseValues.add( dp );
}
}
}
/**
* Calculates (and caches) the initial seasonal indices for the given
* DataSet. Note that there are a variety of ways to estimate initial
* values for the seasonal indices. The approach here averages seasonal
* indices calculated for the first two complete "years" - or cycles - in
* the DataSet.
* @param dataSet the set of data points - observations - to use to
* initialize the seasonal indices.
*/
private void initSeasonalIndices( DataSet dataSet )
{
String timeVariable = getTimeVariable();
double yearlyAverage[] = new double[NUMBER_OF_YEARS];
Iterator it = dataSet.iterator();
for ( int year=0; year it = baseValues.iterator();
while ( it.hasNext() )
{
DataPoint dp = it.next();
double dpTimeValue = dp.getIndependentValue( timeVariable );
if ( Math.abs(time-dpTimeValue) < TOLERANCE )
return dp.getDependentValue();
}
if ( time <
getMinimumTimeValue()
+periodsPerYear*getTimeInterval()
+TOLERANCE )
throw new IllegalArgumentException(
"Attempt to forecast for an invalid time "
+time
+" - before sufficient observations were made ("
+getMinimumTimeValue()
+periodsPerYear*getTimeInterval()+").");
// Saved base value not found, so calculate it
// (and save it for future reference)
double previousTime = time - getTimeInterval();
double previousYear = time - periodsPerYear*getTimeInterval();
double base
= alpha*(getObservedValue(time)/getSeasonalIndex(previousYear))
+ (1-alpha)*(getBase(previousTime)+getTrend(previousTime));
DataPoint dp = new Observation( base );
dp.setIndependentValue( timeVariable, time );
baseValues.add( dp );
return base;
}
/**
* Calculates and returns the trend for the given time period. Except
* for the initial periods - where forecasts are not available - the
* trend is calculated using forecast values, and not observed values.
* See the class documentation for details on the formulation used.
* @param time the time value for which the trend is required.
* @return the trend of the data at the given period of time.
* @param IllegalArgumentException if the trend cannot be determined for
* the given time period.
*/
private double getTrend( double time )
throws IllegalArgumentException
{
// TODO: Optimize this search by having data set sorted by time
// Search for previously calculated - and saved - trend value
String timeVariable = getTimeVariable();
Iterator it = trendValues.iterator();
while ( it.hasNext() )
{
DataPoint dp = it.next();
double dpTimeValue = dp.getIndependentValue( timeVariable );
if ( Math.abs(time-dpTimeValue) < TOLERANCE )
return dp.getDependentValue();
}
if ( time < getMinimumTimeValue()+TOLERANCE )
throw new IllegalArgumentException("Attempt to forecast for an invalid time - before the observations began ("+getMinimumTimeValue()+").");
// Saved trend not found, so calculate it
// (and save it for future reference)
double previousTime = time - getTimeInterval();
double trend
= beta*(getBase(time)-getBase(previousTime))
+ (1-beta)*getTrend(previousTime);
DataPoint dp = new Observation( trend );
dp.setIndependentValue( timeVariable, time );
trendValues.add( dp );
return trend;
}
/**
* Returns the seasonal index for the given time period.
*/
private double getSeasonalIndex( double time )
throws IllegalArgumentException
{
// TODO: Optimize this search by having data set sorted by time
// Handle initial conditions for seasonal index
if ( time
< getMinimumTimeValue()
+(NUMBER_OF_YEARS-1)*periodsPerYear-TOLERANCE )
return getSeasonalIndex( time
+ periodsPerYear*getTimeInterval() );
// Search for previously calculated - and saved - seasonal index
String timeVariable = getTimeVariable();
Iterator it = seasonalIndex.iterator();
while ( it.hasNext() )
{
DataPoint dp = it.next();
double dpTimeValue = dp.getIndependentValue( timeVariable );
if ( Math.abs(time-dpTimeValue) < TOLERANCE )
return dp.getDependentValue();
}
// Saved seasonal index not found, so calculate it
// (and save it for future reference)
double previousYear = time - getTimeInterval()*periodsPerYear;
double index = gamma*(getObservedValue(time)/getForecastValue(time))
+ (1-gamma)*getSeasonalIndex(previousYear);
DataPoint dp = new Observation( index );
dp.setIndependentValue( timeVariable, time );
seasonalIndex.add( dp );
return index;
}
/**
* 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 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 triple exponential smoothing only two
* previous periods are needed - though such a model would be of relatively
* little use. At least ten to fifteen prior observations would be
* preferred.
* @return the minimum number of periods used in this model.
*/
protected int getNumberOfPeriods()
{
return 2*periodsPerYear;
}
/**
* Since this version of triple exponential smoothing uses the current
* observation to calculate a smoothed value, we must override the
* calculation of the accuracy indicators.
* @param dataSet the DataSet to use to evaluate this model, and to
* calculate the accuracy indicators against.
*/
protected void calculateAccuracyIndicators( DataSet dataSet )
{
// WARNING: THIS STILL NEEDS TO BE VALIDATED
// Note that the model has been initialized
initialized = true;
// Reset various helper summations
double sumErr = 0.0;
double sumAbsErr = 0.0;
double sumAbsPercentErr = 0.0;
double sumErrSquared = 0.0;
String timeVariable = getTimeVariable();
double timeDiff = getTimeInterval();
// Calculate the Sum of the Absolute Errors
Iterator it = dataSet.iterator();
while ( it.hasNext() )
{
// Get next data point
DataPoint dp = it.next();
double x = dp.getDependentValue();
double time = dp.getIndependentValue( timeVariable );
double previousTime = time - timeDiff;
// Get next forecast value, using one-period-ahead forecast
double forecastValue
= getForecastValue( previousTime )
+ getTrend( previousTime );
// Calculate error in forecast, and update sums appropriately
double error = forecastValue - x;
sumErr += error;
sumAbsErr += Math.abs( error );
sumAbsPercentErr += Math.abs( error / x );
sumErrSquared += error*error;
}
// Initialize the accuracy indicators
int n = dataSet.size();
accuracyIndicators.setBias( sumErr / n );
accuracyIndicators.setMAD( sumAbsErr / n );
accuracyIndicators.setMAPE( sumAbsPercentErr / n );
accuracyIndicators.setMSE( sumErrSquared / n );
accuracyIndicators.setSAE( sumAbsErr );
}
/**
* Returns the value of the smoothing constant, alpha, used in this model.
* @return the value of the smoothing constant, alpha.
* @see #getBeta
* @see #getGamma
*/
public double getAlpha()
{
return alpha;
}
/**
* Returns the value of the trend smoothing constant, beta, used in this
* model.
* @return the value of the trend smoothing constant, beta.
* @see #getAlpha
* @see #getGamma
*/
public double getBeta()
{
return beta;
}
/**
* Returns the value of the seasonal smoothing constant, gamma, used in
* this model.
* @return the value of the seasonal smoothing constant, gamma.
* @see #getAlpha
* @see #getBeta
*/
public double getGamma()
{
return gamma;
}
/**
* 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 "triple 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 "Triple exponential smoothing model, with smoothing constants of alpha="
+ alpha + ", beta="
+ beta + ", gamma="
+ gamma + ", and using an independent variable of "
+ getIndependentVariable();
}
}
// Local Variables:
// tab-width: 4
// End:
Ads help maintain this website.