source: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs @ 6974

Last change on this file since 6974 was 6974, checked in by gkronber, 8 years ago

#1081: cleared up definition of accuracy metrics for time series prognosis to make the distinction between one n-step forecast and n one-step forecasts clearer. Implemented calculators for time series accuracy metrics to support the calculation of the average accuracy over m n-step forecasts and adapted the unit tests accordingly.

File size: 16.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2011 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System.Collections.Generic;
23using System.Linq;
24using HeuristicLab.Common;
25using HeuristicLab.Data;
26using HeuristicLab.Optimization;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Problems.DataAnalysis {
30  [StorableClass]
31  public abstract class TimeSeriesPrognosisSolutionBase : DataAnalysisSolution, ITimeSeriesPrognosisSolution {
32    private const string TrainingMeanSquaredErrorResultName = "Mean squared error (training)";
33    private const string TestMeanSquaredErrorResultName = "Mean squared error (test)";
34    private const string TrainingMeanAbsoluteErrorResultName = "Mean absolute error (training)";
35    private const string TestMeanAbsoluteErrorResultName = "Mean absolute error (test)";
36    private const string TrainingSquaredCorrelationResultName = "Pearson's R² (training)";
37    private const string TestSquaredCorrelationResultName = "Pearson's R² (test)";
38    private const string TrainingRelativeErrorResultName = "Average relative error (training)";
39    private const string TestRelativeErrorResultName = "Average relative error (test)";
40    private const string TrainingNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (training)";
41    private const string TestNormalizedMeanSquaredErrorResultName = "Normalized mean squared error (test)";
42    private const string TrainingDirectionalSymmetryResultName = "Average directional symmetry (training)";
43    private const string TestDirectionalSymmetryResultName = "Average directional symmetry (test)";
44    private const string TrainingWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (training)";
45    private const string TestWeightedDirectionalSymmetryResultName = "Average weighted directional symmetry (test)";
46    private const string TrainingTheilsUStatisticResultName = "Average Theil's U (training)";
47    private const string TestTheilsUStatisticResultName = "Average Theil's U (test)";
48
49    public new ITimeSeriesPrognosisModel Model {
50      get { return (ITimeSeriesPrognosisModel)base.Model; }
51      protected set { base.Model = value; }
52    }
53
54    public new ITimeSeriesPrognosisProblemData ProblemData {
55      get { return (ITimeSeriesPrognosisProblemData)base.ProblemData; }
56      set { base.ProblemData = value; }
57    }
58
59    public abstract IEnumerable<double> PrognosedValues { get; }
60    public abstract IEnumerable<double> PrognosedTrainingValues { get; }
61    public abstract IEnumerable<double> PrognosedTestValues { get; }
62    public abstract IEnumerable<double> GetPrognosedValues(IEnumerable<int> rows);
63
64    #region Results
65    public double TrainingMeanSquaredError {
66      get { return ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value; }
67      private set { ((DoubleValue)this[TrainingMeanSquaredErrorResultName].Value).Value = value; }
68    }
69    public double TestMeanSquaredError {
70      get { return ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value; }
71      private set { ((DoubleValue)this[TestMeanSquaredErrorResultName].Value).Value = value; }
72    }
73    public double TrainingMeanAbsoluteError {
74      get { return ((DoubleValue)this[TrainingMeanAbsoluteErrorResultName].Value).Value; }
75      private set { ((DoubleValue)this[TrainingMeanAbsoluteErrorResultName].Value).Value = value; }
76    }
77    public double TestMeanAbsoluteError {
78      get { return ((DoubleValue)this[TestMeanAbsoluteErrorResultName].Value).Value; }
79      private set { ((DoubleValue)this[TestMeanAbsoluteErrorResultName].Value).Value = value; }
80    }
81    public double TrainingRSquared {
82      get { return ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value; }
83      private set { ((DoubleValue)this[TrainingSquaredCorrelationResultName].Value).Value = value; }
84    }
85    public double TestRSquared {
86      get { return ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value; }
87      private set { ((DoubleValue)this[TestSquaredCorrelationResultName].Value).Value = value; }
88    }
89    public double TrainingRelativeError {
90      get { return ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value; }
91      private set { ((DoubleValue)this[TrainingRelativeErrorResultName].Value).Value = value; }
92    }
93    public double TestRelativeError {
94      get { return ((DoubleValue)this[TestRelativeErrorResultName].Value).Value; }
95      private set { ((DoubleValue)this[TestRelativeErrorResultName].Value).Value = value; }
96    }
97    public double TrainingNormalizedMeanSquaredError {
98      get { return ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value; }
99      private set { ((DoubleValue)this[TrainingNormalizedMeanSquaredErrorResultName].Value).Value = value; }
100    }
101    public double TestNormalizedMeanSquaredError {
102      get { return ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value; }
103      private set { ((DoubleValue)this[TestNormalizedMeanSquaredErrorResultName].Value).Value = value; }
104    }
105    public double TrainingDirectionalSymmetry {
106      get { return ((DoubleValue)this[TrainingDirectionalSymmetryResultName].Value).Value; }
107      private set { ((DoubleValue)this[TrainingDirectionalSymmetryResultName].Value).Value = value; }
108    }
109    public double TestDirectionalSymmetry {
110      get { return ((DoubleValue)this[TestDirectionalSymmetryResultName].Value).Value; }
111      private set { ((DoubleValue)this[TestDirectionalSymmetryResultName].Value).Value = value; }
112    }
113    public double TrainingWeightedDirectionalSymmetry {
114      get { return ((DoubleValue)this[TrainingWeightedDirectionalSymmetryResultName].Value).Value; }
115      private set { ((DoubleValue)this[TrainingWeightedDirectionalSymmetryResultName].Value).Value = value; }
116    }
117    public double TestWeightedDirectionalSymmetry {
118      get { return ((DoubleValue)this[TestWeightedDirectionalSymmetryResultName].Value).Value; }
119      private set { ((DoubleValue)this[TestWeightedDirectionalSymmetryResultName].Value).Value = value; }
120    }
121    public double TrainingTheilsUStatistic {
122      get { return ((DoubleValue)this[TrainingTheilsUStatisticResultName].Value).Value; }
123      private set { ((DoubleValue)this[TrainingTheilsUStatisticResultName].Value).Value = value; }
124    }
125    public double TestTheilsUStatistic {
126      get { return ((DoubleValue)this[TestTheilsUStatisticResultName].Value).Value; }
127      private set { ((DoubleValue)this[TestTheilsUStatisticResultName].Value).Value = value; }
128    }
129    #endregion
130
131    [StorableConstructor]
132    protected TimeSeriesPrognosisSolutionBase(bool deserializing) : base(deserializing) { }
133    protected TimeSeriesPrognosisSolutionBase(TimeSeriesPrognosisSolutionBase original, Cloner cloner)
134      : base(original, cloner) {
135    }
136    protected TimeSeriesPrognosisSolutionBase(ITimeSeriesPrognosisModel model, ITimeSeriesPrognosisProblemData problemData)
137      : base(model, problemData) {
138      Add(new Result(TrainingMeanSquaredErrorResultName, "Mean of squared errors of the model on the training partition", new DoubleValue()));
139      Add(new Result(TestMeanSquaredErrorResultName, "Mean of squared errors of the model on the test partition", new DoubleValue()));
140      Add(new Result(TrainingMeanAbsoluteErrorResultName, "Mean of absolute errors of the model on the training partition", new DoubleValue()));
141      Add(new Result(TestMeanAbsoluteErrorResultName, "Mean of absolute errors of the model on the test partition", new DoubleValue()));
142      Add(new Result(TrainingSquaredCorrelationResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the training partition", new DoubleValue()));
143      Add(new Result(TestSquaredCorrelationResultName, "Squared Pearson's correlation coefficient of the model output and the actual values on the test partition", new DoubleValue()));
144      Add(new Result(TrainingRelativeErrorResultName, "Average of the relative errors of the model output and the actual values on the training partition", new PercentValue()));
145      Add(new Result(TestRelativeErrorResultName, "Average of the relative errors of the model output and the actual values on the test partition", new PercentValue()));
146      Add(new Result(TrainingNormalizedMeanSquaredErrorResultName, "Normalized mean of squared errors of the model on the training partition", new DoubleValue()));
147      Add(new Result(TestNormalizedMeanSquaredErrorResultName, "Normalized mean of squared errors of the model on the test partition", new DoubleValue()));
148      Add(new Result(TrainingDirectionalSymmetryResultName, "The average directional symmetry of the forecasts of the model on the training partition", new PercentValue()));
149      Add(new Result(TestDirectionalSymmetryResultName, "The average directional symmetry of the forecasts of the model on the test partition", new PercentValue()));
150      Add(new Result(TrainingWeightedDirectionalSymmetryResultName, "The average weighted directional symmetry of the forecasts of the model on the training partition", new DoubleValue()));
151      Add(new Result(TestWeightedDirectionalSymmetryResultName, "The average weighted directional symmetry of the forecasts of the model on the test partition", new DoubleValue()));
152      Add(new Result(TrainingTheilsUStatisticResultName, "The average Theil's U statistic of the forecasts of the model on the training partition", new DoubleValue()));
153      Add(new Result(TestTheilsUStatisticResultName, "The average Theil's U statistic of the forecasts of the model on the test partition", new DoubleValue()));
154    }
155
156    [StorableHook(HookType.AfterDeserialization)]
157    private void AfterDeserialization() {
158
159    }
160
161    protected void CalculateResults() {
162      double[] estimatedTrainingValues = PrognosedTrainingValues.ToArray(); // cache values
163      double[] originalTrainingValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndizes).ToArray();
164      double[] estimatedTestValues = PrognosedTestValues.ToArray(); // cache values
165      double[] originalTestValues = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TestIndizes).ToArray();
166
167      OnlineCalculatorError errorState;
168      double trainingMse = OnlineMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
169      TrainingMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingMse : double.NaN;
170      double testMse = OnlineMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
171      TestMeanSquaredError = errorState == OnlineCalculatorError.None ? testMse : double.NaN;
172
173      double trainingMae = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
174      TrainingMeanAbsoluteError = errorState == OnlineCalculatorError.None ? trainingMae : double.NaN;
175      double testMae = OnlineMeanAbsoluteErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
176      TestMeanAbsoluteError = errorState == OnlineCalculatorError.None ? testMae : double.NaN;
177
178      double trainingR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
179      TrainingRSquared = errorState == OnlineCalculatorError.None ? trainingR2 : double.NaN;
180      double testR2 = OnlinePearsonsRSquaredCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
181      TestRSquared = errorState == OnlineCalculatorError.None ? testR2 : double.NaN;
182
183      double trainingRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
184      TrainingRelativeError = errorState == OnlineCalculatorError.None ? trainingRelError : double.NaN;
185      double testRelError = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
186      TestRelativeError = errorState == OnlineCalculatorError.None ? testRelError : double.NaN;
187
188      double trainingNmse = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
189      TrainingNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? trainingNmse : double.NaN;
190      double testNmse = OnlineNormalizedMeanSquaredErrorCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
191      TestNormalizedMeanSquaredError = errorState == OnlineCalculatorError.None ? testNmse : double.NaN;
192
193      var startTrainingValues = originalTrainingValues;
194      // each continuation is only one element long
195      var actualContinuationsTraining = from x in originalTrainingValues.Skip(1)
196                                        select Enumerable.Repeat(x, 1);
197      // each forecast is only one elemnt long
198      // disregards the first estimated value (we could include this again by extending the list of original values by one step to the left
199      // this is the easier way
200      var predictedContinuationsTraining = from x in estimatedTrainingValues.Skip(1)
201                                           select Enumerable.Repeat(x, 1);
202
203      var startTestValues = originalTestValues;
204      var actualContinuationsTest = from x in originalTestValues.Skip(1)
205                                    select Enumerable.Repeat(x, 1);
206      var predictedContinuationsTest = from x in estimatedTestValues.Skip(1)
207                                       select Enumerable.Repeat(x, 1);
208
209      double trainingDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(startTrainingValues, actualContinuationsTraining, predictedContinuationsTraining, out errorState);
210      TrainingDirectionalSymmetry = errorState == OnlineCalculatorError.None ? trainingDirectionalSymmetry : double.NaN;
211      double testDirectionalSymmetry = OnlineDirectionalSymmetryCalculator.Calculate(startTestValues, actualContinuationsTest, predictedContinuationsTest, out errorState);
212      TestDirectionalSymmetry = errorState == OnlineCalculatorError.None ? testDirectionalSymmetry : double.NaN;
213
214      double trainingWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(startTrainingValues, actualContinuationsTraining, predictedContinuationsTraining, out errorState);
215      TrainingWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? trainingWeightedDirectionalSymmetry : double.NaN;
216      double testWeightedDirectionalSymmetry = OnlineWeightedDirectionalSymmetryCalculator.Calculate(startTestValues, actualContinuationsTest, predictedContinuationsTest, out errorState);
217      TestWeightedDirectionalSymmetry = errorState == OnlineCalculatorError.None ? testWeightedDirectionalSymmetry : double.NaN;
218
219      double trainingTheilsU = OnlineTheilsUStatisticCalculator.Calculate(startTrainingValues, actualContinuationsTraining, predictedContinuationsTraining, out errorState);
220      TrainingTheilsUStatistic = errorState == OnlineCalculatorError.None ? trainingTheilsU : double.NaN;
221      double testTheilsU = OnlineTheilsUStatisticCalculator.Calculate(startTestValues, actualContinuationsTest, predictedContinuationsTest, out errorState);
222      TestTheilsUStatistic = errorState == OnlineCalculatorError.None ? testTheilsU : double.NaN;
223    }
224  }
225}
Note: See TracBrowser for help on using the repository browser.