Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
Provides a time series forecasting environment for Weka. Includes a wrapper for Weka regression schemes that automates the process of creating lagged variables and date-derived periodic variables and provides the ability to do closed-loop forecasting. New evaluation routines are provided by a special evaluation module and graphing of predictions/forecasts are provided via the JFreeChart library. Includes both command-line and GUI user interfaces. Sample time series data can be found in ${WEKA_HOME}/packages/timeseriesForecasting/sample-data.
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
/*
* TSEvaluation.java
* Copyright (C) 2010-2016 University of Waikato, Hamilton, New Zealand
*/
package weka.classifiers.timeseries.eval;
import weka.classifiers.evaluation.NumericPrediction;
import weka.classifiers.timeseries.AbstractForecaster;
import weka.classifiers.timeseries.TSForecaster;
import weka.classifiers.timeseries.WekaForecaster;
import weka.classifiers.timeseries.core.OverlayForecaster;
import weka.filters.supervised.attribute.TSLagMaker;
import weka.classifiers.timeseries.core.TSLagUser;
import weka.classifiers.timeseries.eval.graph.GraphDriver;
import weka.core.Instance;
import weka.core.Instances;
import weka.core.Option;
import weka.core.OptionHandler;
import weka.core.Utils;
import javax.swing.JPanel;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.MethodDescriptor;
import java.io.*;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Main evaluation routines for time series forecasting models. Also provides a
* command line interface for building and evaluating time series models.
*
* @author Mark Hall (mhall{[at]}pentaho{[dot]}com)
* @version $Revision: 52593 $
*/
public class TSEvaluation {
/**
* Number of time steps to forecast out for in each forecasting iteration
* <-horizon>
*/
protected int m_horizon = 1;
/**
* The number of instances to prime the forecaster with prior to each
* forecasting iteration. <-p>
*/
protected int m_primeWindowSize = 1;
/**
* In the case where there is both training and test data available, setting
* this to true will prime the forecaster with the first primeWindowSize
* instances of the test data (instead of the last primeWindowSize instances
* of the training data) before predicting for the test data. This should be
* set to true if the test data does not follow immediately in time from the
* training data. <-primeWithTest>
*/
protected boolean m_primeForTestDataWithTestData = false;
/**
* If true, then the model will be rebuilt after each forecasting iteration on
* the test data. I.e. if N is the training data and t is the first testing
* data point, then then after forecasting t, the model will be
* rebuilt/updated to encompass N + t. Otherwise, the model remains static
* after N and only lagged inputs will be updated using subsequent test data
* points. <-r>
*/
protected boolean m_rebuildModelAfterEachTestForecastStep = false;
/** Forecast future values beyond the end of the series <-f> */
protected boolean m_forecastFuture = true;
/** Evaluate on the training data (if supplied) <-a> */
protected boolean m_evaluateTrainingData = true;
/** Evaluate on the test data (if supplied) <-b> */
protected boolean m_evaluateTestData = true;
/**
* A list of errors (and predictions) for the training data. The list is
* indexed by step (i.e. the first element holds the errors/predictions that
* are one-step-ahead, the second holds those that are two-steps-ahead etc.).
*/
protected List m_predictionsForTrainingData;
/**
* A list of errors (and predictions) for the test data. The list is indexed
* by step (i.e. the first element holds the errors/predictions that are
* one-step-ahead, the second holds those that are two-steps-ahead etc.).
*/
protected List m_predictionsForTestData;
/** Predictions for time steps beyond the end of the training data */
protected List> m_trainingFuture;
/** Predictions for time steps beyond the end of the test data */
protected List> m_testFuture;
/**
* A map (keyed by metric name) of metrics for the training data. The value
* for a key is a List (indexed by step) of the associated metric.
*/
protected Map> m_metricsForTrainingData;
/**
* A map (keyed by metric name) of metrics for the test data. The value for a
* key is a List (indexed by step) of the associated metric.
*/
protected Map> m_metricsForTestData;
/** The evaluation modules to use */
protected List m_evalModules;
/** The training data */
protected Instances m_trainingData;
/** The test data */
protected Instances m_testData;
protected Instances m_dataStructure;
protected List m_missingTargetListTestSet;
protected List m_missingTimeStampListTestSet;
protected List m_missingTimeStampTestSetRows;
/**
* Constructor.
*
* @param trainingData the training data
* @param testSplitSize the number or percentage of instances to hold out from
* the end of the training data to be test data.
* @throws Exception if a problem occurs.
*/
public TSEvaluation(Instances trainingData, double testSplitSize) throws Exception {
if (trainingData != null) {
Instances train = new Instances(trainingData);
Instances test = null;
if (testSplitSize > 0) {
if (trainingData.numInstances() < 2) {
throw new Exception(
"Need at least 2 training instances to do hold out evaluation!");
}
int numToHoldOut = 0;
int trainSize = 0;
if (testSplitSize >= 1) {
numToHoldOut = (int) testSplitSize;
trainSize = trainingData.numInstances() - numToHoldOut;
if (trainSize <= 0) {
throw new Exception(
"Can't hold out more instances than there is in the data!");
}
} else if (testSplitSize > 0) {
double trainP = 1.0 - testSplitSize;
trainSize = (int) Math.round(trainingData.numInstances() * trainP);
numToHoldOut = trainingData.numInstances() - trainSize;
}
train = new Instances(trainingData, 0, trainSize);
test = new Instances(trainingData, trainSize, numToHoldOut);
} else if (testSplitSize < 0) {
throw new Exception("Testing holdout size can't be less than zero!");
}
setTrainingData(train);
setTestData(test);
} else {
setEvaluateOnTrainingData(false);
}
// default eval modules
setEvaluationModules("MAE,RMSE"); // automatically adds an error module too
// setEvaluationModules(""); // automatically adds an error module too
}
/**
* Constructor.
*
* @param trainingData the training data to use
* @param testData the test data to use
* @throws Exception if a problem occurs.
*/
public TSEvaluation(Instances trainingData, Instances testData) throws Exception {
// training or test data may be null (but not both)
if (trainingData != null && testData != null
&& !trainingData.equalHeaders(testData)) {
throw new Exception("Training and testing data are not compatible!");
}
if (trainingData == null && testData == null) {
throw new Exception("Can't specify null for both training and test data");
}
setTrainingData(trainingData);
setTestData(testData);
// default eval modules
setEvaluationModules("MAE,RMSE"); // automatically adds an error module too
// setEvaluationModules(""); // automatically adds an error module too
}
/**
* Set the training data to use
*
* @param train the training data to use
*/
public void setTrainingData(Instances train) {
if (train == null || train.numInstances() > 0) {
m_trainingData = train;
if (m_trainingData == null) {
m_evaluateTrainingData = false;
}
} else {
m_dataStructure = train;
}
}
/**
* Set the test data to use
*
* @param testData the test data to use
*/
public void setTestData(Instances testData) {
if (testData == null || testData.numInstances() > 0) {
m_testData = testData;
if (m_testData == null) {
m_evaluateTestData = false;
} else {
m_evaluateTestData = true;
}
} else {
m_dataStructure = testData;
m_evaluateTestData = false;
}
}
/**
* Get the training data (if any)
*
* @return the training data or null if none is in use
*/
public Instances getTrainingData() {
return m_trainingData;
}
/**
* Get the test data (if any)
*
* @return the test data or null if none is in use.
*/
public Instances getTestData() {
return m_testData;
}
/**
* Set whether to perform evaluation on the training data
*
* @param evalOnTraining true if evaluation is to be performed on the training
* data
*/
public void setEvaluateOnTrainingData(boolean evalOnTraining) {
m_evaluateTrainingData = evalOnTraining;
}
/**
* Get whether evaluation is to be performed on the training data
*
* @return true if evaluation is to be performed on the training data.
*/
public boolean getEvaluateOnTrainingData() {
return m_evaluateTrainingData;
}
/**
* Set whether to perform evaluation on the training data
*
* @param evalOnTest true if evalution is to be performed on the training data
*/
public void setEvaluateOnTestData(boolean evalOnTest) {
m_evaluateTestData = evalOnTest;
}
/**
* Get whether evaluation is to be performed on the test data.
*
* @return true if evaluation is to be performed on the test data.
*/
public boolean getEvaluateOnTestData() {
return m_evaluateTestData;
}
/**
* Set the horizon - i.e. the number of steps to forecast into the future.
*
* @param horizon the number of steps to forecast into the future
*/
public void setHorizon(int horizon) {
m_horizon = horizon;
}
/**
* Set the size of the priming window - i.e. the number of historical
* instances to be presented to the forecaster before a forecast is requested
*
* @param primeSize the number of instances to prime with
*/
public void setPrimeWindowSize(int primeSize) {
m_primeWindowSize = primeSize;
}
/**
* Get the size of the priming window - i.e. the number of historical
* instances that will be presented to the forecaster before a forecast is
* requested.
*
* @return the size of the priming window.
*/
public int getPrimeWindowSize() {
return m_primeWindowSize;
}
/**
* Set whether evaluation for test data should begin by priming with the first
* x test data instances and then forecasting from step x + 1. This is the
* only option if there is no training data and a model has been deserialized
* from disk. If we have training data, and it occurs immediately before the
* test data in time, then we can prime with the last x instances from the
* training data.
*
* @param p true if we should start evaluation of the test data by priming
* with the first instances from the test data.
*/
public void setPrimeForTestDataWithTestData(boolean p) {
m_primeForTestDataWithTestData = p;
}
/**
* Gets whether evaluation for the test data will begin by priming with the
* first x instances from the test data and then forecasting from step x + 1.
* This is the only option if there is no training data and a model has been
* deserialized from disk. If we have training data, and it occurs immediately
* before the test data in time, then we can prime with the last x instances
* from the training data.
*
* @return true if evaluation of the test data will begin by priming with the
* first x instances from the test data.
*/
public boolean getPrimeForTestDataWithTestData() {
return m_primeForTestDataWithTestData;
}
/**
* Set whether the forecasting model should be rebuilt after each forecasting
* step on the test data using both the training data and test data up to the
* current instance.
*
* @param r true if the forecasting model should be rebuilt after each
* forecasting step on the test data to take into account all data up
* to the current point in time
*/
public void setRebuildModelAfterEachTestForecastStep(boolean r) {
m_rebuildModelAfterEachTestForecastStep = r;
}
/**
* Set whether we should generate a future forecast beyond the end of the
* training and/or test data.
*
* @param future true if future forecasts beyond the end of training/test data
* should be generated.
*/
public void setForecastFuture(boolean future) {
m_forecastFuture = future;
}
/**
* Get whether future forecasts beyond the end of the training and/or test
* data will be generated.
*
* @return true if future forecasts will be generated.
*/
public boolean getForecastFuture() {
return m_forecastFuture;
}
/**
* Set the evaluation modules to use/
*
* @param evalModNames a comma-separated list of evaluation module names.
* @throws Exception if there are unknown evaluation modules requested.
*/
public void setEvaluationModules(String evalModNames) throws Exception {
String[] names = evalModNames.split(",");
m_evalModules = new ArrayList();
// we always want an error module
m_evalModules.add(new ErrorModule());
for (String modName : names) {
if (modName.length() > 0) {
TSEvalModule mod = TSEvalModule.getModule(modName.trim());
if (!mod.equals("Error")) {
m_evalModules.add(mod);
}
}
}
}
/*
* public void setEvaluationModules(List modules) { // check for
* an error module for (TSEvalModule m : modules) {
*
* }
*
* m_evalModules = modules; }
*/
/**
* Get the evaluation modules in use
*
* @return a list of the evaluation modules in use.
*/
public List getEvaluationModules() {
return m_evalModules;
}
/**
* Get predictions for all targets for the specified step number on the
* training data
*
* @param stepNumber number of the step into the future to return predictions
* for
* @return the stepNumber step ahead predictions for all targets
* @throws Exception if there are no predictions available for the training
* data
*/
public ErrorModule getPredictionsForTrainingData(int stepNumber)
throws Exception {
if (m_predictionsForTrainingData == null) {
throw new Exception("No predictions for training data available!");
}
int numSteps = m_predictionsForTrainingData.size();
if (stepNumber > m_predictionsForTrainingData.size()) {
throw new Exception("Only predictions up to " + numSteps
+ (numSteps > 1 ? "steps" : "step") + "-ahead are available");
}
ErrorModule m = m_predictionsForTrainingData.get(stepNumber - 1);
return m;
}
/**
* Get predictions for all targets for the specified step number on the test
* data
*
* @param stepNumber number of the step into the future to return predictions
* for
* @return the stepNumber step ahead predictions for all targets
* @throws Exception if there are no predictions available for the test data
*/
public ErrorModule getPredictionsForTestData(int stepNumber) throws Exception {
if (m_predictionsForTestData == null) {
throw new Exception("No predictions for test data available!");
}
int numSteps = m_predictionsForTestData.size();
if (stepNumber > m_predictionsForTestData.size()) {
throw new Exception("Only predictions up to " + numSteps
+ (numSteps > 1 ? "steps" : "step") + "-ahead are available");
}
ErrorModule m = m_predictionsForTestData.get(stepNumber - 1);
return m;
}
private void setupEvalModules(List predHolders,
Map> evalHolders, List fieldsToForecast) {
for (int i = 0; i < m_horizon; i++) {
ErrorModule e = new ErrorModule();
e.setTargetFields(fieldsToForecast);
predHolders.add(e);
}
for (TSEvalModule m : m_evalModules) {
if (!(m.getEvalName().equals("Error"))) {
String key = m.getEvalName();
List evalForSteps = new ArrayList();
TSEvalModule firstMod = null;
for (int i = 0; i < m_horizon; i++) {
TSEvalModule newMod = TSEvalModule.getModule(key);
newMod.setTargetFields(fieldsToForecast);
if (i == 0) {
firstMod = newMod;
} else {
if (newMod.getEvalName().equals("RRSE")) {
// make relative to the one step ahead RRSE module
((RRSEModule) newMod)
.setRelativeRRSEModule((RRSEModule) firstMod);
} else if (newMod.getEvalName().equals("RAE")) {
((RAEModule) newMod).setRelativeRAEModule((RAEModule) firstMod);
}
}
evalForSteps.add(newMod);
}
evalHolders.put(key, evalForSteps);
}
}
}
private void updateEvalModules(List predHolders,
Map> evalHolders,
List> predsForSteps, int currentInstanceNum,
Instances toPredict) throws Exception {
// errors first
for (int i = 0; i < m_horizon; i++) {
// when using overlay data there will only be as many predictions as there
// are
// instances to predict
if (i < predsForSteps.size()) {
List predsForStepI = predsForSteps.get(i);
if (currentInstanceNum + i < toPredict.numInstances()) {
predHolders.get(i).evaluateForInstance(predsForStepI,
toPredict.instance(currentInstanceNum + i));
} else {
predHolders.get(i).evaluateForInstance(predsForStepI, null);
}
}
}
// other evaluation metrics
for (TSEvalModule m : m_evalModules) {
if (!(m.getEvalName().equals("Error"))) {
String key = m.getEvalName();
List evalForSteps = evalHolders.get(key);
for (int i = 0; i < m_horizon; i++) {
if (i < predsForSteps.size()) {
List predsForStepI = predsForSteps.get(i);
if (currentInstanceNum + i < toPredict.numInstances()) {
evalForSteps.get(i).evaluateForInstance(predsForStepI,
toPredict.instance(currentInstanceNum + i));
} else {
evalForSteps.get(i).evaluateForInstance(predsForStepI, null);
}
}
}
}
}
}
/**
* Evaluate the supplied forecaster. Trains the forecaster if a training set
* has been configured.
*
* @param forecaster the forecaster to evaluate
* @throws Exception if something goes wrong during evaluation
*/
public void evaluateForecaster(TSForecaster forecaster,
PrintStream... progress) throws Exception {
evaluateForecaster(forecaster, true, progress);
}
/**
* Creates overlay data to use during evaluation.
*
* @param forecaster the forecaster being evaluated
* @param source the source instances
* @param start the index of the first instance to be part of the overlay data
* @param numSteps the number of steps to forecast (and hence the number of
* instances to make up the overlay data set
* @return the overlay instances.
*/
protected Instances createOverlayForecastData(TSForecaster forecaster,
Instances source, int start, int numSteps) {
int toCopy = Math.min(numSteps, source.numInstances() - start);
Instances overlay = new Instances(source, start, toCopy);
// set all targets to missing
List fieldsToForecast = AbstractForecaster.stringToList(forecaster
.getFieldsToForecast());
for (int i = 0; i < overlay.numInstances(); i++) {
Instance current = overlay.instance(i);
for (String target : fieldsToForecast) {
current.setValue(overlay.attribute(target), Utils.missingValue());
}
}
return overlay;
}
/**
* Evaluate a forecaster on training and/or test data.
*
* @param forecaster the forecaster to evaluate
* @param buildModel true if the model is to be built (given that there is a
* training data set to build it with)
* @throws Exception if something goes wrong during evaluation
*/
public void evaluateForecaster(TSForecaster forecaster, boolean buildModel,
PrintStream... progress) throws Exception {
m_predictionsForTrainingData = null;
m_predictionsForTestData = null;
m_trainingFuture = null;
m_testFuture = null;
// Initialization for state dependent predictors
forecaster.clearPreviousState();
List