Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis-3.4/StatisticCalculatorsTest.cs @ 7058

Last change on this file since 7058 was 7058, checked in by gkronber, 12 years ago

#1081: added unit tests for directional symmetry and Theil's U and multi-step forecasts

File size: 17.3 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;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Problems.DataAnalysis;
27using Microsoft.VisualStudio.TestTools.UnitTesting;
28namespace HeuristicLab.Problems.DataAnalysis_3_4.Tests {
29
30  [TestClass()]
31  public class StatisticCalculatorsTest {
32    private double[,] testData = new double[,] {
33     {5,1,1,1,2,1,3,1,1,2},
34     {5,4,4,5,7,10,3,2,1,2},
35     {3,1,1,1,2,2,3,1,1,2},
36     {6,8,8,1,3,4,3,7,1,2},
37     {4,1,1,3,2,1,3,1,1,2},
38     {8,10,10,8,7,10,9,7,1,4},           
39     {1,1,1,1,2,10,3,1,1,2},             
40     {2,1,2,1,2,1,3,1,1,2},                 
41     {2,1,1,1,2,1,1,1,5,2},                 
42     {4,2,1,1,2,1,2,1,1,2},                   
43     {1,1,1,1,1,1,3,1,1,2},   
44     {2,1,1,1,2,1,2,1,1,2},                   
45     {5,3,3,3,2,3,4,4,1,4},                         
46     {8,7,5,10,7,9,5,5,4,4},         
47     {7,4,6,4,6,1,4,3,1,4},                         
48     {4,1,1,1,2,1,2,1,1,2},     
49     {4,1,1,1,2,1,3,1,1,2},     
50     {10,7,7,6,4,10,4,1,2,4}, 
51     {6,1,1,1,2,1,3,1,1,2},     
52     {7,3,2,10,5,10,5,4,4,4},   
53     {10,5,5,3,6,7,7,10,1,4}
54      };
55
56    [TestMethod]
57    public void CalculateMeanAndVarianceTest() {
58      System.Random random = new System.Random(31415);
59
60      int n = testData.GetLength(0);
61      int cols = testData.GetLength(1);
62      {
63        for (int col = 0; col < cols; col++) {
64          double scale = random.NextDouble();
65          IEnumerable<double> x = from rows in Enumerable.Range(0, n)
66                                  select testData[rows, col] * scale;
67          double[] xs = x.ToArray();
68          double mean_alglib, variance_alglib;
69          mean_alglib = variance_alglib = 0.0;
70          double tmp = 0;
71
72          alglib.samplemoments(xs, n, out  mean_alglib, out variance_alglib, out tmp, out tmp);
73
74          var calculator = new OnlineMeanAndVarianceCalculator();
75          for (int i = 0; i < n; i++) {
76            calculator.Add(xs[i]);
77          }
78          double mean = calculator.Mean;
79          double variance = calculator.Variance;
80
81          Assert.IsTrue(mean_alglib.IsAlmost(mean));
82          Assert.IsTrue(variance_alglib.IsAlmost(variance));
83        }
84      }
85    }
86
87    [TestMethod]
88    public void CalculatePearsonsRSquaredTest() {
89      System.Random random = new System.Random(31415);
90      int n = testData.GetLength(0);
91      int cols = testData.GetLength(1);
92      for (int c1 = 0; c1 < cols; c1++) {
93        for (int c2 = c1 + 1; c2 < cols; c2++) {
94          {
95            double c1Scale = random.NextDouble() * 1E7;
96            double c2Scale = random.NextDouble() * 1E7;
97            IEnumerable<double> x = from rows in Enumerable.Range(0, n)
98                                    select testData[rows, c1] * c1Scale;
99            IEnumerable<double> y = from rows in Enumerable.Range(0, n)
100                                    select testData[rows, c2] * c2Scale;
101            double[] xs = x.ToArray();
102            double[] ys = y.ToArray();
103            double r2_alglib = alglib.pearsoncorrelation(xs, ys, n);
104            r2_alglib *= r2_alglib;
105
106            var r2Calculator = new OnlinePearsonsRSquaredCalculator();
107            for (int i = 0; i < n; i++) {
108              r2Calculator.Add(xs[i], ys[i]);
109            }
110            double r2 = r2Calculator.RSquared;
111
112            Assert.IsTrue(r2_alglib.IsAlmost(r2));
113          }
114        }
115      }
116    }
117    [TestMethod]
118    public void CalculatePearsonsRSquaredOfConstantTest() {
119      System.Random random = new System.Random(31415);
120      int n = 12;
121      int cols = testData.GetLength(1);
122      for (int c1 = 0; c1 < cols; c1++) {
123        double c1Scale = random.NextDouble() * 1E7;
124        IEnumerable<double> x = from rows in Enumerable.Range(0, n)
125                                select testData[rows, c1] * c1Scale;
126        IEnumerable<double> y = (new List<double>() { 150494407424305.47 })
127          .Concat(Enumerable.Repeat(150494407424305.47, n - 1));
128        double[] xs = x.ToArray();
129        double[] ys = y.ToArray();
130        double r2_alglib = alglib.pearsoncorrelation(xs, ys, n);
131        r2_alglib *= r2_alglib;
132
133        var r2Calculator = new OnlinePearsonsRSquaredCalculator();
134        for (int i = 0; i < n; i++) {
135          r2Calculator.Add(xs[i], ys[i]);
136        }
137        double r2 = r2Calculator.RSquared;
138
139        Assert.AreEqual(r2_alglib.ToString(), r2.ToString());
140      }
141    }
142
143    [TestMethod]
144    public void CalculateDirectionalSymmetryTest() {
145      // delta: +0.01, +1, -0.01, -2, -0.01, -1, +0.01, +2
146      var original = new double[]
147                       {
148                         0,
149                         0.01,
150                         1.01,
151                         1,
152                         -1,
153                         -1.01,
154                         -2.01,
155                         -2,
156                         0
157                       };
158      // delta to original(t-1): +1, +0, -1, -0, -1, +0.01, +0.01, +2
159      var estimated = new double[]
160                        {
161                          -1,
162                          1,
163                          0.01,
164                          0.01,
165                          1,
166                          -1,
167                          -1.02,
168                          -2.02,
169                          0
170                        };
171
172      // one-step forecast
173      var startValues = original;
174      var actualContinuations = from x in original.Skip(1)
175                                select Enumerable.Repeat(x, 1);
176      var predictedContinuations = from x in estimated.Skip(1)
177                                   select Enumerable.Repeat(x, 1);
178      double expected = 0.5;  // half of the predicted deltas are correct
179      OnlineCalculatorError errorState;
180      double actual = OnlineDirectionalSymmetryCalculator.Calculate(startValues, actualContinuations, predictedContinuations, out errorState);
181      Assert.AreEqual(expected, actual, 1E-9);
182    }
183
184    [TestMethod]
185    public void CalculateMultiStepDirectionalSymmetryTest() {
186      // delta: +0.01, +1, -0.01, -2, -0.01, -1, +0.01, +2
187      var original = new double[] { 0, 0.01, 1.01, 1, -1, -1.01, -2.01, -2, 0 };
188      {
189        var estimated = new double[][]
190                          {
191                            new double[] {0.01, 1.01, 1, -1, -1.01},
192                            new double[] {1.01, 1, -1, -1.01, -2.01},
193                            new double[] {1, -1, -1.01, -2.01, -2},
194                            new double[] {-1, -1.01, -2.01, -2, 0}
195                          };
196
197        // 5-step forecast
198        var startValues = original.Take(4);
199        var actualContinuations = from i in Enumerable.Range(1, original.Count() - 5)
200                                  select original.Skip(i).Take(5);
201        var predictedContinuations = estimated;
202        double expected = 1; // predictions are 100% correct
203        OnlineCalculatorError errorState;
204        double actual = OnlineDirectionalSymmetryCalculator.Calculate(startValues, actualContinuations,
205                                                                      predictedContinuations, out errorState);
206        Assert.AreEqual(expected, actual, 1E-9);
207      }
208      {
209        // only the direction is relevant
210        var estimated = new double[][]
211                          {
212                            new double[] {0.01, 0.01, 0.01, -0.01, -0.01},  // start=0, original deltas: 0.01, 1.01, 1.00, -1.00, -1.01
213                            new double[] {0.02, 0.02, 0.00, 0.00, 0.00}, // start=0.01, original deltas: 1.00, 0.90, -1.01, -1.02, -2.02,
214                            new double[] { 1.00, 1.00, 1.00, 1.00, 1.00}, // start=1.01, original deltas: -0.01, -2.01, -2.02, -3.02, -3.01
215                            new double[] { 0.90, 0.90, 0.90, 0.90, 0.90}  // start=1, original deltas: -2.00, -0.01, -3.01, -3.00, -1.00
216                          };
217
218        // 5-step forecast
219        var startValues = original.Take(4);
220        var actualContinuations = from i in Enumerable.Range(1, original.Count() - 5)
221                                  select original.Skip(i).Take(5);
222        var predictedContinuations = estimated;
223        double expected = 1; // half of the predicted deltas are correct
224        OnlineCalculatorError errorState;
225        double actual = OnlineDirectionalSymmetryCalculator.Calculate(startValues, actualContinuations,
226                                                                      predictedContinuations, out errorState);
227        Assert.AreEqual(expected, actual, 1E-9);
228      }
229      {
230        // also check incorrectly predicted directions
231        var estimated = new double[][]
232                          {
233                            new double[] {0.01, 0.01, 0.01, +0.01, +0.01},  // start=0, original deltas: 0.01, 1.01, 1.00, -1.00, -1.01
234                            new double[] {0.02, 0.00, 0.02, 0.00, 0.00}, // start=0.01, original deltas: 1.00, 0.90, -1.01, -1.02, -2.02,
235                            new double[] { 1.02, 1.00, 1.02, 1.00, 1.02}, // start=1.01, original deltas: -0.01, -2.01, -2.02, -3.02, -3.01
236                            new double[] { 0.90, 0.90, 0.90, 0.90, 0.90}  // start=1, original deltas: -2.00, -0.01, -3.01, -3.00, -1.00
237                          };
238
239        // 5-step forecast
240        var startValues = original.Take(4);
241        var actualContinuations = from i in Enumerable.Range(1, original.Count() - 5)
242                                  select original.Skip(i).Take(5);
243        var predictedContinuations = estimated;
244        double expected = (20 - 7) / 20.0; // half of the predicted deltas are correct
245        OnlineCalculatorError errorState;
246        double actual = OnlineDirectionalSymmetryCalculator.Calculate(startValues, actualContinuations,
247                                                                      predictedContinuations, out errorState);
248        Assert.AreEqual(expected, actual, 1E-9);
249      }
250    }
251
252
253    [TestMethod]
254    public void CalculateWeightedDirectionalSymmetryTest() {
255      var original = new double[] { 0, 0.01, 1.01, 1, -1, -1.01, -2.01, -2, 0 }; // +0.01, +1, -0.01, -2, -0.01, -1, +0.01, +2
256      var estimated = new double[] { 1, 2, 2, 1, 1, 0, 0.01, 0.02, 2.02 }; // delta to original: +2, +1.99, -0.01, 0, +1, -1.02, +2.01, +4.02
257      // one-step forecast
258      var startValues = original;
259      var actualContinuations = from x in original.Skip(1)
260                                select Enumerable.Repeat(x, 1);
261      var predictedContinuations = from x in estimated.Skip(1)
262                                   select Enumerable.Repeat(x, 1);
263      // absolute errors = 1.99, 0.99, 0, 2, 1.01, 2.02, 2.02, 2.02     
264      // sum of absolute errors for correctly predicted deltas = 2.97
265      // sum of absolute errors for incorrectly predicted deltas = 3.03
266      double expected = 5.03 / 7.02;
267      OnlineCalculatorError errorState;
268      double actual = OnlineWeightedDirectionalSymmetryCalculator.Calculate(startValues, actualContinuations, predictedContinuations, out errorState);
269      Assert.AreEqual(expected, actual, 1E-9);
270    }
271
272    [TestMethod]
273    public void CalculateTheilsUTest() {
274      var original = new double[] { 0, 0.01, 1.01, 1, -1, -1.01, -2.01, -2, 0 };
275      var estimated = new double[] { 1, 1.01, 0.01, 2, 0, -0.01, -1.01, -3, 1 };
276      // one-step forecast
277      var startValues = original;
278      var actualContinuations = from x in original.Skip(1)
279                                select Enumerable.Repeat(x, 1);
280      var predictedContinuations = from x in estimated.Skip(1)
281                                   select Enumerable.Repeat(x, 1);
282      // Sum of squared errors of model y(t+1) = y(t) = 10.0004
283      // Sum of squared errors of predicted values = 8 
284      double expected = Math.Sqrt(8 / 10.0004);
285      OnlineCalculatorError errorState;
286      double actual = OnlineTheilsUStatisticCalculator.Calculate(startValues, actualContinuations, predictedContinuations, out errorState);
287      Assert.AreEqual(expected, actual, 1E-9);
288    }
289
290    [TestMethod]
291    public void CalculateMultiStepTheilsUTest() {
292      var original = new double[] { 0, 0.01, 1.01, 1, -1, -1.01, -2.01, -2, 0 };
293      {
294        // prefect prediction
295        var estimated = new double[][]
296                          {
297                            new double[] {0.01, 1.01, 1, -1, -1.01},
298                            new double[] {1.01, 1, -1, -1.01, -2.01},
299                            new double[] {1, -1, -1.01, -2.01, -2},
300                            new double[] {-1, -1.01, -2.01, -2, 0}
301                          };
302        // 5-step forecast
303        var startValues = original.Take(4);
304        var actualContinuations = from i in Enumerable.Range(1, original.Count() - 5)
305                                  select original.Skip(i).Take(5);
306        var predictedContinuations = estimated;
307
308        double expected = 0;
309        OnlineCalculatorError errorState;
310        double actual = OnlineTheilsUStatisticCalculator.Calculate(startValues, actualContinuations,
311                                                                   predictedContinuations, out errorState);
312        Assert.AreEqual(expected, actual, 1E-9);
313      }
314      {
315        // naive prediction
316        var estimated = new double[][]
317                          {
318                            new double[] {0, 0, 0, 0, 0},
319                            new double[] {0.01, 0.01, 0.01, 0.01, 0.01},
320                            new double[] {1.01, 1.01, 1.01, 1.01, 1.01},
321                            new double[] {1, 1, 1, 1, 1}
322                          };
323        // 5-step forecast
324        var startValues = original.Take(4);
325        var actualContinuations = from i in Enumerable.Range(1, original.Count() - 5)
326                                  select original.Skip(i).Take(5);
327        var predictedContinuations = estimated;
328
329        double expected = 1;
330        OnlineCalculatorError errorState;
331        double actual = OnlineTheilsUStatisticCalculator.Calculate(startValues, actualContinuations,
332                                                                   predictedContinuations, out errorState);
333        Assert.AreEqual(expected, actual, 1E-9);
334      }
335      {
336        // realistic prediction
337        var estimated = new double[][]
338                          {
339                            new double[] {0.005, 0.5, 0.5, -0.5, -0.5},    // start = 0
340                            new double[] {0.60, 0.5, -0.5, -0.5, -1},   // start = 0.01
341                            new double[] {-0.005, 0, 0, -0.5, -1},     // start = 1.01
342                            new double[] {-0, 0, -0.5, -1, 0.5}      // start = 1
343                          };
344        // 5-step forecast
345        var startValues = original.Take(4);
346        var actualContinuations = from i in Enumerable.Range(1, original.Count() - 5)
347                                  select original.Skip(i).Take(5);
348        var predictedContinuations = estimated;
349
350        double expected = 0.47558387;
351        OnlineCalculatorError errorState;
352        double actual = OnlineTheilsUStatisticCalculator.Calculate(startValues, actualContinuations,
353                                                                   predictedContinuations, out errorState);
354        Assert.AreEqual(expected, actual, 1E-6);
355      }
356    }
357
358    [TestMethod]
359    public void CalculateAccuracyTest() {
360      var original = new double[] { 1, 1, 0, 0 };
361      var estimated = new double[] { 1, 0, 1, 0 };
362      double expected = 0.5;
363      OnlineCalculatorError errorState;
364      double actual = OnlineAccuracyCalculator.Calculate(original, estimated, out errorState);
365      Assert.AreEqual(expected, actual, 1E-9);
366    }
367
368    [TestMethod]
369    public void CalculateMeanAbsolutePercentageErrorTest() {
370      var original = new double[] { 1, 2, 3, 1, 5 };
371      var estimated = new double[] { 2, 1, 3, 1, 0 };
372      double expected = 0.5;
373      OnlineCalculatorError errorState;
374      double actual = OnlineMeanAbsolutePercentageErrorCalculator.Calculate(original, estimated, out errorState);
375      Assert.AreEqual(expected, actual, 1E-9);
376      Assert.AreEqual(OnlineCalculatorError.None, errorState);
377
378      // if the original contains zero values the result is not defined
379      var original2 = new double[] { 1, 2, 0, 0, 0 };
380      OnlineMeanAbsolutePercentageErrorCalculator.Calculate(original2, estimated, out errorState);
381      Assert.AreEqual(OnlineCalculatorError.InvalidValueAdded, errorState);
382    }
383  }
384}
Note: See TracBrowser for help on using the repository browser.