Ignore:
Timestamp:
08/01/18 14:01:08 (3 years ago)
Author:
fholzing
Message:

#2904: Streamlined the variableimpactcalculator code on both Regression and Classification. Taken over the regression-code for classification with some minor adaptations.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2904_CalculateImpacts/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionVariableImpactsView.cs

    r15753 r16036  
    3333  [Content(typeof(IClassificationSolution))]
    3434  public partial class ClassificationSolutionVariableImpactsView : DataAnalysisSolutionEvaluationView {
    35     #region Nested Types
    3635    private enum SortingCriteria {
    3736      ImpactValue,
     
    3938      VariableName
    4039    }
    41     #endregion
    42 
    43     #region Fields
    44     private Dictionary<string, double> rawVariableImpacts = new Dictionary<string, double>();
    45     private Thread thread;
    46     #endregion
    47 
    48     #region Getter/Setter
     40    private CancellationTokenSource cancellationToken = new CancellationTokenSource();
     41    private List<Tuple<string, double>> rawVariableImpacts = new List<Tuple<string, double>>();
     42
    4943    public new IClassificationSolution Content {
    5044      get { return (IClassificationSolution)base.Content; }
     
    5347      }
    5448    }
    55     #endregion
    56 
    57     #region Ctor
     49
    5850    public ClassificationSolutionVariableImpactsView()
    5951      : base() {
    6052      InitializeComponent();
    6153
    62       //Little workaround. If you fill the ComboBox-Items in the other partial class, the UI-Designer will moan.
    63       this.sortByComboBox.Items.AddRange(Enum.GetValues(typeof(SortingCriteria)).Cast<object>().ToArray());
    64       this.sortByComboBox.SelectedItem = SortingCriteria.ImpactValue;
    65 
    6654      //Set the default values
    6755      this.dataPartitionComboBox.SelectedIndex = 0;
    68       this.replacementComboBox.SelectedIndex = 0;
     56      this.replacementComboBox.SelectedIndex = 3;
    6957      this.factorVarReplComboBox.SelectedIndex = 0;
    70     }
    71     #endregion
    72 
    73     #region Events
     58      this.sortByComboBox.SelectedItem = SortingCriteria.ImpactValue;
     59    }
     60
    7461    protected override void RegisterContentEvents() {
    7562      base.RegisterContentEvents();
     
    7764      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
    7865    }
    79 
    8066    protected override void DeregisterContentEvents() {
    8167      base.DeregisterContentEvents();
     
    8773      OnContentChanged();
    8874    }
    89 
    9075    protected virtual void Content_ModelChanged(object sender, EventArgs e) {
    9176      OnContentChanged();
    9277    }
    93 
    9478    protected override void OnContentChanged() {
    9579      base.OnContentChanged();
     
    10084      }
    10185    }
    102 
    10386    private void ClassificationSolutionVariableImpactsView_VisibleChanged(object sender, EventArgs e) {
    104       if (thread == null) { return; }
    105 
    106       if (thread.IsAlive) { thread.Abort(); }
    107       thread = null;
    108     }
    109 
     87      cancellationToken.Cancel();
     88    }
    11089
    11190    private void dataPartitionComboBox_SelectedIndexChanged(object sender, EventArgs e) {
    11291      UpdateVariableImpact();
    11392    }
    114 
    11593    private void replacementComboBox_SelectedIndexChanged(object sender, EventArgs e) {
    11694      UpdateVariableImpact();
    11795    }
    118 
    11996    private void sortByComboBox_SelectedIndexChanged(object sender, EventArgs e) {
    12097      //Update the default ordering (asc,desc), but remove the eventHandler beforehand (otherwise the data would be ordered twice)
    12198      ascendingCheckBox.CheckedChanged -= ascendingCheckBox_CheckedChanged;
    122       switch ((SortingCriteria)sortByComboBox.SelectedItem) {
    123         case SortingCriteria.ImpactValue:
    124           ascendingCheckBox.Checked = false;
    125           break;
    126         case SortingCriteria.Occurrence:
    127           ascendingCheckBox.Checked = true;
    128           break;
    129         case SortingCriteria.VariableName:
    130           ascendingCheckBox.Checked = true;
    131           break;
    132         default:
    133           throw new NotImplementedException("Ordering for selected SortingCriteria not implemented");
    134       }
     99      ascendingCheckBox.Checked = (SortingCriteria)sortByComboBox.SelectedItem != SortingCriteria.ImpactValue;
    135100      ascendingCheckBox.CheckedChanged += ascendingCheckBox_CheckedChanged;
    136101
    137       UpdateDataOrdering();
    138     }
    139 
     102      UpdateOrdering();
     103    }
    140104    private void ascendingCheckBox_CheckedChanged(object sender, EventArgs e) {
    141       UpdateDataOrdering();
    142     }
    143 
    144     #endregion
    145 
    146     #region Helper Methods   
    147     private void UpdateVariableImpact() {
     105      UpdateOrdering();
     106    }
     107
     108    private async void UpdateVariableImpact() {
    148109      //Check if the selection is valid
    149110      if (Content == null) { return; }
     
    152113      if (factorVarReplComboBox.SelectedIndex < 0) { return; }
    153114
     115      IProgress progress;
     116
    154117      //Prepare arguments
    155118      var mainForm = (MainForm.WindowsForms.MainForm)MainFormManager.MainForm;
     
    159122
    160123      variableImactsArrayView.Caption = Content.Name + " Variable Impacts";
    161 
    162       mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
    163 
    164       Task.Factory.StartNew(() => {
    165         thread = Thread.CurrentThread;
    166         //Remember the original ordering of the variables
    167         var impacts = ClassificationSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod, factorReplMethod);
     124      progress = mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
     125      progress.ProgressValue = 0;
     126
     127      cancellationToken = new CancellationTokenSource();
     128
     129      try {
    168130        var problemData = Content.ProblemData;
    169131        var inputvariables = new HashSet<string>(problemData.AllowedInputVariables.Union(Content.Model.VariablesUsedForPrediction));
    170         var originalVariableOrdering = problemData.Dataset.VariableNames.Where(v => inputvariables.Contains(v)).Where(problemData.Dataset.VariableHasType<double>).ToList();
     132        //Remember the original ordering of the variables
     133        var originalVariableOrdering = problemData.Dataset.VariableNames
     134          .Where(v => inputvariables.Contains(v))
     135          .Where(v => problemData.Dataset.VariableHasType<double>(v) || problemData.Dataset.VariableHasType<string>(v))
     136          .ToList();
     137
     138        List<Tuple<string, double>> impacts = null;
     139
     140        await Task.Run(() => { impacts = CalculateVariableImpacts(originalVariableOrdering, (IClassificationModel)Content.Model.Clone(), problemData, Content.EstimatedClassValues, dataPartition, replMethod, factorReplMethod, cancellationToken.Token, progress); });
     141        if (impacts == null) { return; }
    171142
    172143        rawVariableImpacts.Clear();
    173         originalVariableOrdering.ForEach(v => rawVariableImpacts.Add(v, impacts.First(vv => vv.Item1 == v).Item2));
    174       }).ContinueWith((o) => {
    175         UpdateDataOrdering();
    176         mainForm.RemoveOperationProgressFromView(this);
    177         thread = null;
    178       }, TaskScheduler.FromCurrentSynchronizationContext());
     144        originalVariableOrdering.ForEach(v => rawVariableImpacts.Add(new Tuple<string, double>(v, impacts.First(vv => vv.Item1 == v).Item2)));
     145        UpdateOrdering();
     146      }
     147      finally {
     148        ((MainForm.WindowsForms.MainForm)MainFormManager.MainForm).RemoveOperationProgressFromView(this);
     149      }
     150    }
     151
     152    private List<Tuple<string, double>> CalculateVariableImpacts(List<string> originalVariableOrdering,
     153      IClassificationModel model,
     154      IClassificationProblemData problemData,
     155      IEnumerable<double> estimatedValues,
     156      ClassificationSolutionVariableImpactsCalculator.DataPartitionEnum dataPartition,
     157      ClassificationSolutionVariableImpactsCalculator.ReplacementMethodEnum replMethod,
     158      ClassificationSolutionVariableImpactsCalculator.FactorReplacementMethodEnum factorReplMethod,
     159      CancellationToken token,
     160      IProgress progress) {
     161      List<Tuple<string, double>> impacts = new List<Tuple<string, double>>();
     162      int count = originalVariableOrdering.Count;
     163      int i = 0;
     164      var modifiableDataset = ((Dataset)(problemData.Dataset).Clone()).ToModifiable();
     165      IEnumerable<int> rows = ClassificationSolutionVariableImpactsCalculator.GetPartitionRows(dataPartition, problemData);
     166
     167      //Calculate original quality-values (via calculator, default is R²)
     168      OnlineCalculatorError error;
     169      IEnumerable<double> targetValuesPartition = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows);
     170      IEnumerable<double> estimatedValuesPartition = rows.Select(v => estimatedValues.ElementAt(v));
     171      var originalCalculatorValue = ClassificationSolutionVariableImpactsCalculator.CalculateVariableImpact(targetValuesPartition, estimatedValuesPartition, out error);
     172      if (error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during calculation.");
     173
     174      foreach (var variableName in originalVariableOrdering) {
     175        if (cancellationToken.Token.IsCancellationRequested) { return null; }
     176        progress.ProgressValue = (double)++i / count;
     177        progress.Status = string.Format("Calculating impact for variable {0} ({1} of {2})", variableName, i, count);
     178
     179        double impact = ClassificationSolutionVariableImpactsCalculator.CalculateImpact(variableName, model, modifiableDataset, rows, targetValuesPartition, originalCalculatorValue, replMethod, factorReplMethod);
     180        impacts.Add(new Tuple<string, double>(variableName, impact));
     181      }
     182
     183      return impacts;
    179184    }
    180185
     
    183188    /// The default is "Descending" by "VariableImpact" (as in previous versions)
    184189    /// </summary>
    185     private void UpdateDataOrdering() {
     190    private void UpdateOrdering() {
    186191      //Check if valid sortingCriteria is selected and data exists
    187192      if (sortByComboBox.SelectedIndex == -1) { return; }
     
    192197      bool ascending = ascendingCheckBox.Checked;
    193198
    194       IEnumerable<KeyValuePair<string, double>> orderedEntries = null;
     199      IEnumerable<Tuple<string, double>> orderedEntries = null;
    195200
    196201      //Sort accordingly
    197202      switch (selectedItem) {
    198203        case SortingCriteria.ImpactValue:
    199           orderedEntries = rawVariableImpacts.OrderBy(v => v.Value);
     204          orderedEntries = rawVariableImpacts.OrderBy(v => v.Item2);
    200205          break;
    201206        case SortingCriteria.Occurrence:
     
    203208          break;
    204209        case SortingCriteria.VariableName:
    205           orderedEntries = rawVariableImpacts.OrderBy(v => v.Key, new NaturalStringComparer());
     210          orderedEntries = rawVariableImpacts.OrderBy(v => v.Item1, new NaturalStringComparer());
    206211          break;
    207212        default:
     
    212217
    213218      //Write the data back
    214       var impactArray = new DoubleArray(orderedEntries.Select(i => i.Value).ToArray()) {
    215         ElementNames = orderedEntries.Select(i => i.Key)
     219      var impactArray = new DoubleArray(orderedEntries.Select(i => i.Item2).ToArray()) {
     220        ElementNames = orderedEntries.Select(i => i.Item1)
    216221      };
    217222
     
    221226      }
    222227    }
    223     #endregion 
    224228  }
    225229}
Note: See TracChangeset for help on using the changeset viewer.