Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs	(revision 14507)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Dataset.cs	(revision 14826)
@@ -168,4 +168,9 @@
       get { return variableValues.Where(p => p.Value is List<double>).Select(p => p.Key); }
     }
+
+    public IEnumerable<string> StringVariables {
+      get { return variableValues.Where(p => p.Value is List<string>).Select(p => p.Key); }
+    }
+
     public IEnumerable<double> GetDoubleValues(string variableName) {
       return GetValues<double>(variableName);
@@ -189,4 +194,18 @@
       return GetValues<double>(variableName, rows);
     }
+
+    public string GetStringValue(string variableName, int row) {
+      var values = GetValues<string>(variableName);
+      return values[row];
+    }
+
+    public IEnumerable<string> GetStringValues(string variableName, IEnumerable<int> rows) {
+      return GetValues<string>(variableName, rows);
+    }
+    public ReadOnlyCollection<string> GetReadOnlyStringValues(string variableName) {
+      var values = GetValues<string>(variableName);
+      return values.AsReadOnly();
+    }
+
     private IEnumerable<T> GetValues<T>(string variableName, IEnumerable<int> rows) {
       var values = GetValues<T>(variableName);
Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 14507)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/DataAnalysisProblemData.cs	(revision 14826)
@@ -152,10 +152,11 @@
     protected DataAnalysisProblemData(IDataset dataset, IEnumerable<string> allowedInputVariables, IEnumerable<ITransformation> transformations = null) {
       if (dataset == null) throw new ArgumentNullException("The dataset must not be null.");
-      if (allowedInputVariables == null) throw new ArgumentNullException("The allowedInputVariables must not be null.");
-
-      if (allowedInputVariables.Except(dataset.DoubleVariables).Any())
-        throw new ArgumentException("All allowed input variables must be present in the dataset and of type double.");
-
-      var inputVariables = new CheckedItemList<StringValue>(dataset.DoubleVariables.Select(x => new StringValue(x)));
+      if (allowedInputVariables == null) throw new ArgumentNullException("The allowed input variables must not be null.");
+
+      if (allowedInputVariables.Except(dataset.DoubleVariables).Except(dataset.StringVariables).Any())
+        throw new ArgumentException("All allowed input variables must be present in the dataset and of type double or string.");
+
+      var variables = dataset.VariableNames.Where(variable => dataset.VariableHasType<double>(variable) || dataset.VariableHasType<string>(variable));
+      var inputVariables = new CheckedItemList<StringValue>(variables.Select(x => new StringValue(x)));
       foreach (StringValue x in inputVariables)
         inputVariables.SetItemCheckedState(x, allowedInputVariables.Contains(x.Value));
Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 14507)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionSolutionVariableImpactsCalculator.cs	(revision 14826)
@@ -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 replacement = ReplacementMethodEnum.Median) {
+      ReplacementMethodEnum replacementMethod = ReplacementMethodEnum.Median,
+      FactorReplacementMethodEnum factorReplacementMethod = FactorReplacementMethodEnum.Best) {
 
       var problemData = solution.ProblemData;
@@ -128,6 +134,7 @@
       var allowedInputVariables = dataset.VariableNames.Where(v => inputvariables.Contains(v)).ToList();
 
-      foreach (var inputVariable in allowedInputVariables) {
-        var newEstimates = EvaluateModelWithReplacedVariable(solution.Model, inputVariable, modifiableDataset, rows, replacement);
+      // calculate impacts for double variables
+      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.");
@@ -137,4 +144,37 @@
         impacts[inputVariable] = impact;
       }
+
+      // 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.");
+
+          newR2 = newR2 * newR2;
+          var impact = originalR2 - newR2;
+          impacts[inputVariable] = impact;
+        }
+      } // foreach
       return impacts.OrderByDescending(i => i.Value).Select(i => Tuple.Create(i.Key, i.Value));
     }
@@ -184,5 +224,47 @@
       }
 
-      dataset.ReplaceVariable(variable, replacementValues);
+      return EvaluateModelWithReplacedVariable(model, variable, dataset, rows, replacementValues);
+    }
+
+    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();
+      dataset.ReplaceVariable(variable, replacementValues.ToList());
       //mkommend: ToList is used on purpose to avoid lazy evaluation that could result in wrong estimates due to variable replacements
       var estimates = model.GetEstimatedValues(dataset, rows).ToList();
@@ -191,4 +273,14 @@
       return estimates;
     }
+    private static IEnumerable<double> EvaluateModelWithReplacedVariable(IRegressionModel model, string variable,
+      ModifiableDataset dataset, IEnumerable<int> rows, IEnumerable<string> replacementValues) {
+      var originalValues = dataset.GetReadOnlyStringValues(variable).ToList();
+      dataset.ReplaceVariable(variable, replacementValues.ToList());
+      //mkommend: ToList is used on purpose to avoid lazy evaluation that could result in wrong estimates due to variable replacements
+      var estimates = model.GetEstimatedValues(dataset, rows).ToList();
+      dataset.ReplaceVariable(variable, originalValues);
+
+      return estimates;
+    }
   }
 }
Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataset.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataset.cs	(revision 14507)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Interfaces/IDataset.cs	(revision 14826)
@@ -30,4 +30,7 @@
     IEnumerable<string> VariableNames { get; }
     IEnumerable<string> DoubleVariables { get; }
+    IEnumerable<string> StringVariables { get; }
+
+    bool VariableHasType<T>(string variableName);
 
     double GetDoubleValue(string variableName, int row);
@@ -36,5 +39,9 @@
     ReadOnlyCollection<double> GetReadOnlyDoubleValues(string variableName);
 
+    string GetStringValue(string variableName, int row);
     IEnumerable<string> GetStringValues(string variableName);
+    IEnumerable<string> GetStringValues(string variableName, IEnumerable<int> rows);
+    ReadOnlyCollection<string> GetReadOnlyStringValues(string VariableName);
+
     IEnumerable<DateTime> GetDateTimeValues(string variableName);
   }
Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/ModifiableDataset.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/ModifiableDataset.cs	(revision 14507)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/ModifiableDataset.cs	(revision 14826)
@@ -77,5 +77,5 @@
     public void ReplaceVariable(string variableName, IList values) {
       if (!variableValues.ContainsKey(variableName))
-        throw new ArgumentException(string.Format("Variable {0} is not present in the dataset."), variableName);
+        throw new ArgumentException(string.Format("Variable {0} is not present in the dataset.", variableName));
       if (values.Count != variableValues[variableName].Count)
         throw new ArgumentException("The number of values must coincide with the number of dataset rows.");
