Index: /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.Designer.cs
===================================================================
--- /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.Designer.cs	(revision 14761)
+++ /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.Designer.cs	(revision 14762)
@@ -47,6 +47,8 @@
       this.dataPartitionComboBox = new System.Windows.Forms.ComboBox();
       this.dataPartitionLabel = new System.Windows.Forms.Label();
-      this.replacementLabel = new System.Windows.Forms.Label();
+      this.numericVarReplacementLabel = new System.Windows.Forms.Label();
       this.replacementComboBox = new System.Windows.Forms.ComboBox();
+      this.factorVarReplacementLabel = new System.Windows.Forms.Label();
+      this.factorVarReplComboBox = new System.Windows.Forms.ComboBox();
       this.SuspendLayout();
       // 
@@ -58,9 +60,9 @@
       this.variableImactsArrayView.Caption = "StringConvertibleArray View";
       this.variableImactsArrayView.Content = null;
-      this.variableImactsArrayView.Location = new System.Drawing.Point(3, 59);
+      this.variableImactsArrayView.Location = new System.Drawing.Point(3, 84);
       this.variableImactsArrayView.Name = "variableImactsArrayView";
       this.variableImactsArrayView.ReadOnly = true;
-      this.variableImactsArrayView.Size = new System.Drawing.Size(304, 223);
-      this.variableImactsArrayView.TabIndex = 4;
+      this.variableImactsArrayView.Size = new System.Drawing.Size(363, 278);
+      this.variableImactsArrayView.TabIndex = 2;
       // 
       // dataPartitionComboBox
@@ -71,5 +73,5 @@
             HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.Test,
             HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.DataPartitionEnum.All});
-      this.dataPartitionComboBox.Location = new System.Drawing.Point(82, 3);
+      this.dataPartitionComboBox.Location = new System.Drawing.Point(197, 3);
       this.dataPartitionComboBox.Name = "dataPartitionComboBox";
       this.dataPartitionComboBox.Size = new System.Drawing.Size(121, 21);
@@ -86,12 +88,12 @@
       this.dataPartitionLabel.Text = "Data partition:";
       // 
-      // replacementLabel
+      // numericVarReplacementLabel
       // 
-      this.replacementLabel.AutoSize = true;
-      this.replacementLabel.Location = new System.Drawing.Point(3, 35);
-      this.replacementLabel.Name = "replacementLabel";
-      this.replacementLabel.Size = new System.Drawing.Size(73, 13);
-      this.replacementLabel.TabIndex = 2;
-      this.replacementLabel.Text = "Replacement:";
+      this.numericVarReplacementLabel.AutoSize = true;
+      this.numericVarReplacementLabel.Location = new System.Drawing.Point(3, 33);
+      this.numericVarReplacementLabel.Name = "numericVarReplacementLabel";
+      this.numericVarReplacementLabel.Size = new System.Drawing.Size(173, 13);
+      this.numericVarReplacementLabel.TabIndex = 2;
+      this.numericVarReplacementLabel.Text = "Replacement for numeric variables:";
       // 
       // replacementComboBox
@@ -103,5 +105,5 @@
             HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum.Noise,
             HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum.Shuffle});
-      this.replacementComboBox.Location = new System.Drawing.Point(82, 32);
+      this.replacementComboBox.Location = new System.Drawing.Point(197, 30);
       this.replacementComboBox.Name = "replacementComboBox";
       this.replacementComboBox.Size = new System.Drawing.Size(121, 21);
@@ -109,15 +111,39 @@
       this.replacementComboBox.SelectedIndexChanged += new System.EventHandler(this.replacementComboBox_SelectedIndexChanged);
       // 
+      // factorVarReplacementLabel
+      // 
+      this.factorVarReplacementLabel.AutoSize = true;
+      this.factorVarReplacementLabel.Location = new System.Drawing.Point(3, 60);
+      this.factorVarReplacementLabel.Name = "factorVarReplacementLabel";
+      this.factorVarReplacementLabel.Size = new System.Drawing.Size(188, 13);
+      this.factorVarReplacementLabel.TabIndex = 0;
+      this.factorVarReplacementLabel.Text = "Replacement for categorical variables:";
+      // 
+      // factorVarReplComboBox
+      // 
+      this.factorVarReplComboBox.FormattingEnabled = true;
+      this.factorVarReplComboBox.Items.AddRange(new object[] {
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Best,
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Mode,
+            HeuristicLab.Problems.DataAnalysis.RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum.Shuffle});
+      this.factorVarReplComboBox.Location = new System.Drawing.Point(197, 57);
+      this.factorVarReplComboBox.Name = "factorVarReplComboBox";
+      this.factorVarReplComboBox.Size = new System.Drawing.Size(121, 21);
+      this.factorVarReplComboBox.TabIndex = 1;
+      this.factorVarReplComboBox.SelectedIndexChanged += new System.EventHandler(this.replacementComboBox_SelectedIndexChanged);
+      // 
       // RegressionSolutionVariableImpactsView
       // 
       this.AllowDrop = true;
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.factorVarReplComboBox);
+      this.Controls.Add(this.factorVarReplacementLabel);
       this.Controls.Add(this.replacementComboBox);
-      this.Controls.Add(this.replacementLabel);
+      this.Controls.Add(this.numericVarReplacementLabel);
       this.Controls.Add(this.dataPartitionLabel);
       this.Controls.Add(this.dataPartitionComboBox);
       this.Controls.Add(this.variableImactsArrayView);
       this.Name = "RegressionSolutionVariableImpactsView";
-      this.Size = new System.Drawing.Size(310, 285);
+      this.Size = new System.Drawing.Size(369, 365);
       this.ResumeLayout(false);
       this.PerformLayout();
@@ -130,6 +156,8 @@
     private System.Windows.Forms.ComboBox dataPartitionComboBox;
     private System.Windows.Forms.Label dataPartitionLabel;
-    private System.Windows.Forms.Label replacementLabel;
+    private System.Windows.Forms.Label numericVarReplacementLabel;
     private System.Windows.Forms.ComboBox replacementComboBox;
+    private System.Windows.Forms.Label factorVarReplacementLabel;
+    private System.Windows.Forms.ComboBox factorVarReplComboBox;
   }
 }
Index: /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs
===================================================================
--- /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs	(revision 14761)
+++ /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionVariableImpactsView.cs	(revision 14762)
@@ -43,5 +43,6 @@
       this.dataPartitionComboBox.SelectedIndex = 0;
       this.replacementComboBox.SelectedIndex = 0;
-    }
+      this.factorVarReplComboBox.SelectedIndex = 0;
+      }
 
     #region events
@@ -68,5 +69,5 @@
     protected override void OnContentChanged() {
       base.OnContentChanged();
-      if (Content == null) {
+      if(Content == null) {
         variableImactsArrayView.Content = null;
       } else {
@@ -76,9 +77,15 @@
 
     private void UpdateVariableImpacts() {
-      if (Content == null || replacementComboBox.SelectedIndex < 0 || dataPartitionComboBox.SelectedIndex < 0) return;
+      if(Content == null || replacementComboBox.SelectedIndex < 0
+        || factorVarReplComboBox.SelectedIndex < 0
+        || dataPartitionComboBox.SelectedIndex < 0) return;
       var mainForm = (MainForm.WindowsForms.MainForm)MainFormManager.MainForm;
       variableImactsArrayView.Caption = Content.Name + " Variable Impacts";
       var replMethod =
-         (RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum)replacementComboBox.Items[replacementComboBox.SelectedIndex];
+         (RegressionSolutionVariableImpactsCalculator.ReplacementMethodEnum)
+           replacementComboBox.Items[replacementComboBox.SelectedIndex];
+      var factorReplMethod =
+        (RegressionSolutionVariableImpactsCalculator.FactorReplacementMethodEnum)
+          factorVarReplComboBox.Items[factorVarReplComboBox.SelectedIndex];
       var dataPartition =
         (RegressionSolutionVariableImpactsCalculator.DataPartitionEnum)dataPartitionComboBox.SelectedItem;
@@ -88,5 +95,5 @@
           mainForm.AddOperationProgressToView(this, "Calculating variable impacts for " + Content.Name);
 
-          var impacts = RegressionSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod);
+          var impacts = RegressionSolutionVariableImpactsCalculator.CalculateImpacts(Content, dataPartition, replMethod, factorReplMethod);
           var impactArray = new DoubleArray(impacts.Select(i => i.Item2).ToArray());
           impactArray.ElementNames = impacts.Select(i => i.Item1);
Index: /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs
===================================================================
--- /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 14761)
+++ /branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 14762)
@@ -42,5 +42,9 @@
       Noise
     }
-
+    public enum FactorReplacementMethodEnum {
+      Best,
+      Mode,
+      Shuffle
+    }
     public enum DataPartitionEnum {
       Training,
@@ -88,7 +92,9 @@
     }
 
-    public static IEnumerable<Tuple<string, double>> CalculateImpacts(IRegressionSolution solution,
+    public static IEnumerable<Tuple<string, double>> CalculateImpacts(
+      IRegressionSolution solution,
       DataPartitionEnum data = DataPartitionEnum.Training,
-      ReplacementMethodEnum replacementMethod = ReplacementMethodEnum.Median) {
+      ReplacementMethodEnum replacementMethod = ReplacementMethodEnum.Median,
+      FactorReplacementMethodEnum factorReplacementMethod = FactorReplacementMethodEnum.Best) {
 
       var problemData = solution.ProblemData;
@@ -101,10 +107,10 @@
       OnlineCalculatorError error;
 
-      switch (data) {
+      switch(data) {
         case DataPartitionEnum.All:
           rows = solution.ProblemData.AllIndices;
           targetValues = problemData.TargetVariableValues.ToList();
           originalR2 = OnlinePearsonsRCalculator.Calculate(problemData.TargetVariableValues, solution.EstimatedValues, out error);
-          if (error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during R² calculation.");
+          if(error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during R² calculation.");
           originalR2 = originalR2 * originalR2;
           break;
@@ -129,8 +135,8 @@
 
       // calculate impacts for double variables
-      foreach (var inputVariable in allowedInputVariables.Where(problemData.Dataset.VariableHasType<double>)) {
+      foreach(var inputVariable in allowedInputVariables.Where(problemData.Dataset.VariableHasType<double>)) {
         var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows, replacementMethod);
         var newR2 = OnlinePearsonsRCalculator.Calculate(targetValues, newEstimates, out error);
-        if (error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during R² calculation with replaced inputs.");
+        if(error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during R² calculation with replaced inputs.");
 
         newR2 = newR2 * newR2;
@@ -138,18 +144,37 @@
         impacts[inputVariable] = impact;
       }
-      // calculate impacts for factor variables
-      foreach (var inputVariable in allowedInputVariables.Where(problemData.Dataset.VariableHasType<string>)) {
-        var smallestImpact = double.PositiveInfinity;
-        foreach (var repl in problemData.Dataset.GetStringValues(inputVariable, rows).Distinct()) {
-          var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows, Enumerable.Repeat(repl, dataset.Rows));
+
+      // calculate impacts for string variables
+      foreach(var inputVariable in allowedInputVariables.Where(problemData.Dataset.VariableHasType<string>)) {
+        if(factorReplacementMethod == FactorReplacementMethodEnum.Best) {
+          // try replacing with all possible values and find the best replacement value
+          var smallestImpact = double.PositiveInfinity;
+          foreach(var repl in problemData.Dataset.GetStringValues(inputVariable, rows).Distinct()) {
+            var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows,
+              Enumerable.Repeat(repl, dataset.Rows));
+            var newR2 = OnlinePearsonsRCalculator.Calculate(targetValues, newEstimates, out error);
+            if(error != OnlineCalculatorError.None)
+              throw new InvalidOperationException("Error during R² calculation with replaced inputs.");
+
+            newR2 = newR2 * newR2;
+            var impact = originalR2 - newR2;
+            if(impact < smallestImpact) smallestImpact = impact;
+          }
+          impacts[inputVariable] = smallestImpact;
+        } else {
+          // for replacement methods shuffle and mode
+          // calculate impacts for factor variables
+
+          var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows,
+            factorReplacementMethod);
           var newR2 = OnlinePearsonsRCalculator.Calculate(targetValues, newEstimates, out error);
-          if (error != OnlineCalculatorError.None) throw new InvalidOperationException("Error during R² calculation with replaced inputs.");
+          if(error != OnlineCalculatorError.None)
+            throw new InvalidOperationException("Error during R² calculation with replaced inputs.");
 
           newR2 = newR2 * newR2;
           var impact = originalR2 - newR2;
-          if (impact < smallestImpact) smallestImpact = impact;
+          impacts[inputVariable] = impact;
         }
-        impacts[inputVariable] = smallestImpact;
-      }
+      } // foreach
       return impacts.OrderByDescending(i => i.Value).Select(i => Tuple.Create(i.Key, i.Value));
     }
@@ -161,5 +186,5 @@
       IRandom rand;
 
-      switch (replacement) {
+      switch(replacement) {
         case ReplacementMethodEnum.Median:
           replacementValue = rows.Select(r => originalValues[r]).Median();
@@ -179,5 +204,5 @@
           int i = 0;
           // update column values 
-          foreach (var r in rows) {
+          foreach(var r in rows) {
             replacementValues[r] = shuffledValues[i++];
           }
@@ -190,5 +215,5 @@
           replacementValues = Enumerable.Repeat(double.NaN, dataset.Rows).ToList();
           // update column values 
-          foreach (var r in rows) {
+          foreach(var r in rows) {
             replacementValues[r] = NormalDistributedRandom.NextDouble(rand, avg, stdDev);
           }
@@ -202,5 +227,41 @@
     }
 
-    private static IEnumerable<double> EvaluateModelWithReplacedVariable(IRegressionModel model, string variable, 
+    private static IEnumerable<double> EvaluateModelWithReplacedVariable(
+      IRegressionModel model, string variable, ModifiableDataset dataset,
+      IEnumerable<int> rows,
+      FactorReplacementMethodEnum replacement = FactorReplacementMethodEnum.Shuffle) {
+      var originalValues = dataset.GetReadOnlyStringValues(variable).ToList();
+      List<string> replacementValues;
+      IRandom rand;
+
+      switch(replacement) {
+        case FactorReplacementMethodEnum.Mode:
+          var mostCommonValue = rows.Select(r => originalValues[r])
+            .GroupBy(v => v)
+            .OrderByDescending(g => g.Count())
+            .First().Key;
+          replacementValues = Enumerable.Repeat(mostCommonValue, dataset.Rows).ToList();
+          break;
+        case FactorReplacementMethodEnum.Shuffle:
+          // new var has same empirical distribution but the relation to y is broken
+          rand = new FastRandom(31415);
+          // prepare a complete column for the dataset
+          replacementValues = Enumerable.Repeat(string.Empty, dataset.Rows).ToList();
+          // shuffle only the selected rows
+          var shuffledValues = rows.Select(r => originalValues[r]).Shuffle(rand).ToList();
+          int i = 0;
+          // update column values 
+          foreach(var r in rows) {
+            replacementValues[r] = shuffledValues[i++];
+          }
+          break;
+        default:
+          throw new ArgumentException(string.Format("FactorReplacementMethod {0} cannot be handled.", replacement));
+      }
+
+      return EvaluateModelWithReplacedVariable(model, variable, dataset, rows, replacementValues);
+    }
+
+    private static IEnumerable<double> EvaluateModelWithReplacedVariable(IRegressionModel model, string variable,
       ModifiableDataset dataset, IEnumerable<int> rows, IEnumerable<double> replacementValues) {
       var originalValues = dataset.GetReadOnlyDoubleValues(variable).ToList();
@@ -212,5 +273,5 @@
       return estimates;
     }
-    private static IEnumerable<double> EvaluateModelWithReplacedVariable(IRegressionModel model, string variable, 
+    private static IEnumerable<double> EvaluateModelWithReplacedVariable(IRegressionModel model, string variable,
       ModifiableDataset dataset, IEnumerable<int> rows, IEnumerable<string> replacementValues) {
       var originalValues = dataset.GetReadOnlyStringValues(variable).ToList();
