Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3136_Structural_GP/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SingleObjective/SolutionQualityAnalyzer.cs @ 18190

Last change on this file since 18190 was 18053, checked in by gkronber, 3 years ago

#3135 added a new analyzer which allows to configure the solution result name, and renamed and marked the existing SolutionRSquaredAnalyzer as obsolete.

File size: 6.4 KB
Line 
1#region License Information
2
3/* HeuristicLab
4 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
5 *
6 * This file is part of HeuristicLab.
7 *
8 * HeuristicLab is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * HeuristicLab is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#endregion
23
24using System.Linq;
25using HeuristicLab.Analysis;
26using HeuristicLab.Common;
27using HeuristicLab.Core;
28using HeuristicLab.Data;
29using HeuristicLab.Operators;
30using HeuristicLab.Optimization;
31using HeuristicLab.Parameters;
32using HEAL.Attic;
33using System;
34
35namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Regression {
36  /// <summary>
37  /// Finds all RegressionSolutions in a ResultCollection and extracts the DoubleValue of a result (an optionally a secondary result) for each solution.
38  /// All values are tracked in a single DataTable over generations.
39  /// This can be used to extract training and test NMSE for the best solution for a chart of training/test NMSE over generations.
40  /// </summary>
41  [StorableType("52047D25-C042-4773-B12D-AB67DD707AE6")]
42  public sealed class SolutionQualityAnalyzer : SingleSuccessorOperator, IAnalyzer {
43    private const string ResultCollectionParameterName = "Results";
44    private const string SolutionResultsResultName = "Solution Results";
45    private const string DefaultTrainingResultName = "Normalized mean squared error (training)";
46    private const string DefaultTestResultName = "Normalized mean squared error (test)"; // use NMSE instead of R². R² is too optimistic for the test (assumes perfect scaling).
47
48    public ILookupParameter<ResultCollection> ResultCollectionParameter {
49      get { return (ILookupParameter<ResultCollection>)Parameters[ResultCollectionParameterName]; }
50    }
51    public ILookupParameter<DoubleValue> ResultParameter {
52      get { return (ILookupParameter<DoubleValue>)Parameters[DefaultTrainingResultName]; }
53    }
54    public ILookupParameter<DoubleValue> SecondaryResultParameter {
55      get { return (ILookupParameter<DoubleValue>)Parameters[DefaultTestResultName]; }
56    }
57
58    public bool EnabledByDefault {
59      get { return false; }
60    }
61
62    [StorableConstructor]
63    private SolutionQualityAnalyzer(StorableConstructorFlag _) : base(_) { }
64    private SolutionQualityAnalyzer(SolutionQualityAnalyzer original, Cloner cloner)
65      : base(original, cloner) { }
66    public override IDeepCloneable Clone(Cloner cloner) {
67      return new SolutionQualityAnalyzer(this, cloner);
68    }
69
70    public SolutionQualityAnalyzer() {
71      Parameters.Add(new LookupParameter<ResultCollection>(ResultCollectionParameterName, "The result collection to store the analysis results."));
72      Parameters.Add(new LookupParameter<DoubleValue>(DefaultTrainingResultName, $"First solution result name (default: {DefaultTrainingResultName})."));
73      Parameters.Add(new LookupParameter<DoubleValue>(DefaultTestResultName, $"Second solution result name (default: {DefaultTestResultName}). This is optional. Leave empty if not used."));
74    }
75
76    public override IOperation Apply() {
77      var results = ResultCollectionParameter.ActualValue;
78
79      if (!results.ContainsKey(SolutionResultsResultName)) {
80        var newDataTable = new DataTable(SolutionResultsResultName);
81        results.Add(new Result(SolutionResultsResultName, "Chart of solution result values of all regression solutions.", newDataTable));
82      }
83
84      var dataTable = (DataTable)results[SolutionResultsResultName].Value;
85
86      // store actual names of parameter because they are changed below
87      var resultParameter = ResultParameter;
88      string savedResultParamName = resultParameter.ActualName;
89      var secondaryResultParameter = SecondaryResultParameter;
90      string savedSecondaryResultParamName = secondaryResultParameter.ActualName;
91      try {
92        foreach (var result in results.Where(r => r.Value is RegressionSolution)) {
93          var solution = (RegressionSolution)result.Value;
94
95          var resultRowName = result.Name + " " + savedResultParamName;
96          var resultValue = solution[savedResultParamName].Value as DoubleValue;
97          if (resultValue == null) throw new ArgumentException($"SolutionQualityAnalyzer: the selected result ({savedResultParamName}) is no DoubleValue");
98
99          if (!dataTable.Rows.ContainsKey(resultRowName))
100            dataTable.Rows.Add(new DataRow(resultRowName));
101
102          dataTable.Rows[resultRowName].Values.Add(resultValue.Value);
103          // HACK: we change the ActualName of the parameter to write the results for each solution to the scope
104          resultParameter.ActualName = resultRowName;
105          resultParameter.ActualValue = new DoubleValue(resultValue.Value);
106
107          // same for the second result if it is given
108          if (!string.IsNullOrWhiteSpace(savedSecondaryResultParamName)) {
109            var secondaryResultRowName = result.Name + " " + savedSecondaryResultParamName;
110            var secondaryResultValue = solution[savedSecondaryResultParamName].Value as DoubleValue;
111            if (secondaryResultValue == null) throw new ArgumentException($"SolutionQualityAnalyzer: the selected result ({savedSecondaryResultParamName}) is no DoubleValue");
112
113            if (!dataTable.Rows.ContainsKey(secondaryResultRowName))
114              dataTable.Rows.Add(new DataRow(secondaryResultRowName));
115
116            dataTable.Rows[secondaryResultRowName].Values.Add(secondaryResultValue.Value);
117            secondaryResultParameter.ActualName = secondaryResultRowName;
118            secondaryResultParameter.ActualValue = new DoubleValue(secondaryResultValue.Value);
119          }
120        }
121      } finally {
122        // restore saved parameter names
123        resultParameter.ActualName = savedResultParamName;
124        secondaryResultParameter.ActualName = savedSecondaryResultParamName;
125      }
126      return base.Apply();
127    }
128  }
129}
Note: See TracBrowser for help on using the repository browser.