Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs @ 17387

Last change on this file since 17387 was 17276, checked in by fholzing, 5 years ago

#2973: Changed cancelation-initiation from VisibleChanged to OnHidden and added a flag, preventing an error in case the View gets closed.

File size: 10.2 KB
RevLine 
[14348]1#region License Information
2/* HeuristicLab
[17180]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[14348]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
[15665]21
[14348]22using System;
[15626]23using System.Collections.Generic;
[14348]24using System.Linq;
[15797]25using System.Threading;
26using System.Threading.Tasks;
[15637]27using HeuristicLab.Common;
[14348]28using HeuristicLab.Data;
29using HeuristicLab.MainForm;
30
31namespace HeuristicLab.Problems.DataAnalysis.Views {
32  [View("Variable Impacts")]
33  [Content(typeof(IRegressionSolution))]
34  public partial class RegressionSolutionVariableImpactsView : DataAnalysisSolutionEvaluationView {
[15673]35    private enum SortingCriteria {
36      ImpactValue,
37      Occurrence,
38      VariableName
39    }
[16422]40    private CancellationTokenSource cancellationToken = new CancellationTokenSource();
[15998]41    private List<Tuple<string, double>> rawVariableImpacts = new List<Tuple<string, double>>();
[17276]42    private bool attachedToProgress = false;
[15626]43
[14348]44    public new IRegressionSolution Content {
45      get { return (IRegressionSolution)base.Content; }
46      set {
47        base.Content = value;
48      }
49    }
50
51    public RegressionSolutionVariableImpactsView()
52      : base() {
53      InitializeComponent();
[15665]54
[15727]55      //Set the default values
[14348]56      this.dataPartitionComboBox.SelectedIndex = 0;
[16021]57      this.replacementComboBox.SelectedIndex = 3;
[14826]58      this.factorVarReplComboBox.SelectedIndex = 0;
[15998]59      this.sortByComboBox.SelectedItem = SortingCriteria.ImpactValue;
[14348]60    }
61
62    protected override void RegisterContentEvents() {
63      base.RegisterContentEvents();
64      Content.ModelChanged += new EventHandler(Content_ModelChanged);
65      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
66    }
67    protected override void DeregisterContentEvents() {
68      base.DeregisterContentEvents();
69      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
70      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
71    }
72
73    protected virtual void Content_ProblemDataChanged(object sender, EventArgs e) {
74      OnContentChanged();
75    }
76    protected virtual void Content_ModelChanged(object sender, EventArgs e) {
77      OnContentChanged();
78    }
79    protected override void OnContentChanged() {
80      base.OnContentChanged();
[16422]81      rawVariableImpacts.Clear();
82
[14348]83      if (Content == null) {
[16422]84        variableImpactsArrayView.Content = null;
[14348]85      } else {
[15752]86        UpdateVariableImpact();
[14348]87      }
88    }
[17276]89
90    protected override void OnHidden(EventArgs e) {
91      base.OnHidden(e);
[15998]92      cancellationToken.Cancel();
[17276]93
94      if (attachedToProgress) {
95        Progress.Hide(this);
96        attachedToProgress = false;
97      }
[15752]98    }
99
[15665]100    private void dataPartitionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
[16422]101      rawVariableImpacts.Clear();
[15752]102      UpdateVariableImpact();
[15665]103    }
104    private void replacementComboBox_SelectedIndexChanged(object sender, EventArgs e) {
[16422]105      rawVariableImpacts.Clear();
[15752]106      UpdateVariableImpact();
[15665]107    }
108    private void sortByComboBox_SelectedIndexChanged(object sender, EventArgs e) {
109      //Update the default ordering (asc,desc), but remove the eventHandler beforehand (otherwise the data would be ordered twice)
110      ascendingCheckBox.CheckedChanged -= ascendingCheckBox_CheckedChanged;
[15998]111      ascendingCheckBox.Checked = (SortingCriteria)sortByComboBox.SelectedItem != SortingCriteria.ImpactValue;
[15665]112      ascendingCheckBox.CheckedChanged += ascendingCheckBox_CheckedChanged;
113
[15998]114      UpdateOrdering();
[15665]115    }
116    private void ascendingCheckBox_CheckedChanged(object sender, EventArgs e) {
[15998]117      UpdateOrdering();
[15665]118    }
[15727]119
[15797]120    private async void UpdateVariableImpact() {
[15727]121      //Check if the selection is valid
[15673]122      if (Content == null) { return; }
123      if (replacementComboBox.SelectedIndex < 0) { return; }
124      if (dataPartitionComboBox.SelectedIndex < 0) { return; }
125      if (factorVarReplComboBox.SelectedIndex < 0) { return; }
126
[15727]127      //Prepare arguments
[15673]128      var replMethod = (RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum)replacementComboBox.Items[replacementComboBox.SelectedIndex];
129      var factorReplMethod = (RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum)factorVarReplComboBox.Items[factorVarReplComboBox.SelectedIndex];
130      var dataPartition = (RegressionSolutionVariableImpactsCalculator.DataPartitionEnum)dataPartitionComboBox.SelectedItem;
131
[16422]132      variableImpactsArrayView.Caption = Content.Name + " Variable Impacts";
[16430]133      var progress = Progress.Show(this, "Calculating variable impacts for " + Content.Name);
[17276]134      attachedToProgress = true;
[15797]135      cancellationToken = new CancellationTokenSource();
[16422]136
[15797]137      try {
138        var problemData = Content.ProblemData;
139        var inputvariables = new HashSet<string>(problemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
[16422]140        //Remember the original ordering of the variables
[16015]141        var originalVariableOrdering = problemData.Dataset.VariableNames
142          .Where(v => inputvariables.Contains(v))
143          .Where(v => problemData.Dataset.VariableHasType<double>(v) || problemData.Dataset.VariableHasType<string>(v))
144          .ToList();
[15797]145
[16422]146        List<Tuple<string, double>> impacts = null;
147        await Task.Run(() => { impacts = CalculateVariableImpacts(originalVariableOrdering, Content.Model, problemData, Content.EstimatedValues, dataPartition, replMethod, factorReplMethod, cancellationToken.Token, progress); });
148        if (impacts == null) { return; }
149
150        rawVariableImpacts.AddRange(impacts);
[15998]151        UpdateOrdering();
[17276]152      } finally {
153        if (attachedToProgress) {
154          Progress.Hide(this);
155          attachedToProgress = false;
156        }
[16422]157      }
[14348]158    }
[16422]159    private List<Tuple<string, double>> CalculateVariableImpacts(List<string> originalVariableOrdering,
160      IRegressionModel model,
161      IRegressionProblemData problemData,
162      IEnumerable<double> estimatedValues,
163      RegressionSolutionVariableImpactsCalculator.DataPartitionEnum dataPartition,
164      RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum replMethod,
165      RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum factorReplMethod,
166      CancellationToken token,
167      IProgress progress) {
168      List<Tuple<string, double>> impacts = new List<Tuple<string, double>>();
169      int count = originalVariableOrdering.Count;
170      int i = 0;
171      var modifiableDataset = ((Dataset)(problemData.Dataset).Clone()).ToModifiable();
172      IEnumerable<int> rows = RegressionSolutionVariableImpactsCalculator.GetPartitionRows(dataPartition, problemData);
[14348]173
[16422]174      //Calculate original quality-values (via calculator, default is R²)
175      IEnumerable<double> targetValuesPartition = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
176      IEnumerable<double> estimatedValuesPartition = Content.GetEstimatedValues(rows);
177
178      var originalCalculatorValue = RegressionSolutionVariableImpactsCalculator.CalculateQuality(targetValuesPartition, estimatedValuesPartition);
179
180      foreach (var variableName in originalVariableOrdering) {
181        if (cancellationToken.Token.IsCancellationRequested) { return null; }
182        progress.ProgressValue = (double)++i / count;
[16430]183        progress.Message = string.Format("Calculating impact for variable {0} ({1} of {2})", variableName, i, count);
[16422]184
185        double impact = 0;
186        //If the variable isn't used for prediction, it has zero impact.
187        if (model.VariablesUsedForPrediction.Contains(variableName)) {
188          impact = RegressionSolutionVariableImpactsCalculator.CalculateImpact(variableName, model, problemData, modifiableDataset, rows, replMethod, factorReplMethod, targetValuesPartition, originalCalculatorValue);
189        }
190        impacts.Add(new Tuple<string, double>(variableName, impact));
191      }
192
193      return impacts;
194    }
195
[15626]196    /// <summary>
[16422]197    /// Updates the <see cref="variableImpactsArrayView"/> according to the selected ordering <see cref="ascendingCheckBox"/> of the selected Column <see cref="sortByComboBox"/>
[15626]198    /// The default is "Descending" by "VariableImpact" (as in previous versions)
199    /// </summary>
[15998]200    private void UpdateOrdering() {
[15665]201      //Check if valid sortingCriteria is selected and data exists
[15673]202      if (sortByComboBox.SelectedIndex == -1) { return; }
203      if (rawVariableImpacts == null) { return; }
204      if (!rawVariableImpacts.Any()) { return; }
[15665]205
[15673]206      var selectedItem = (SortingCriteria)sortByComboBox.SelectedItem;
[15626]207      bool ascending = ascendingCheckBox.Checked;
208
[15998]209      IEnumerable<Tuple<string, double>> orderedEntries = null;
[15626]210
[15665]211      //Sort accordingly
212      switch (selectedItem) {
[15673]213        case SortingCriteria.ImpactValue:
[15998]214          orderedEntries = rawVariableImpacts.OrderBy(v => v.Item2);
[15665]215          break;
[15673]216        case SortingCriteria.Occurrence:
217          orderedEntries = rawVariableImpacts;
[15665]218          break;
[15673]219        case SortingCriteria.VariableName:
[15998]220          orderedEntries = rawVariableImpacts.OrderBy(v => v.Item1, new NaturalStringComparer());
[15665]221          break;
222        default:
[15673]223          throw new NotImplementedException("Ordering for selected SortingCriteria not implemented");
[15626]224      }
225
[15673]226      if (!ascending) { orderedEntries = orderedEntries.Reverse(); }
227
[15665]228      //Write the data back
[15998]229      var impactArray = new DoubleArray(orderedEntries.Select(i => i.Item2).ToArray()) {
230        ElementNames = orderedEntries.Select(i => i.Item1)
[15665]231      };
[15727]232
[15752]233      //Could be, if the View was closed
[16422]234      if (!variableImpactsArrayView.IsDisposed) {
235        variableImpactsArrayView.Content = (DoubleArray)impactArray.AsReadOnly();
[15727]236      }
[15626]237    }
[14348]238  }
239}
Note: See TracBrowser for help on using the repository browser.