Index: /branches/DataPreprocessing Cleanup/DataPreprocessing Cleanup.sln
===================================================================
--- /branches/DataPreprocessing Cleanup/DataPreprocessing Cleanup.sln	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/DataPreprocessing Cleanup.sln	(revision 15431)
@@ -2,5 +2,5 @@
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
-VisualStudioVersion = 15.0.26430.16
+VisualStudioVersion = 15.0.26430.15
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.DataPreprocessing-3.4", "HeuristicLab.DataPreprocessing\3.4\HeuristicLab.DataPreprocessing-3.4.csproj", "{3B90F866-70F8-43EF-A541-51819D255B7B}"
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing.Views/3.4/StatisticsView.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing.Views/3.4/StatisticsView.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing.Views/3.4/StatisticsView.cs	(revision 15431)
@@ -92,6 +92,6 @@
       numericColumnsTextBox.Text = GetColumnCount<double>().ToString();
       nominalColumnsTextBox5.Text = GetColumnCount<string>().ToString();
-      missingValuesTextBox.Text = data.DataColumns.Sum(c => c.GetNumberOfMissingValues()).ToString();
-      totalValuesTextBox.Text = (data.Rows * data.Rows - data.DataColumns.Sum(c => c.GetNumberOfMissingValues())).ToString();
+      missingValuesTextBox.Text = data.GetMissingValueCount().ToString();
+      totalValuesTextBox.Text = (data.Rows * data.Rows - data.GetMissingValueCount()).ToString();
 
       var variableNames = Content.PreprocessingData.VariableNames.ToList();
@@ -111,7 +111,7 @@
         for (int j = 0; j < statistics.Count; j++) {
           if (horizontal)
-            statisticsMatrix[j, i] = statistics[j].ToString();
+            statisticsMatrix[j, i] = statistics[j];
           else
-            statisticsMatrix[i, j] = statistics[j].ToString();
+            statisticsMatrix[i, j] = statistics[j];
         }
       }
@@ -148,6 +148,6 @@
     }
 
-    private IList GetStatistics(int varIdx) {
-      IList list;
+    private List<string> GetStatistics(int varIdx) {
+      List<string> list;
       var data = Content.PreprocessingData;
       if (data.VariableHasType<double>(varIdx)) {
@@ -166,55 +166,55 @@
     }
 
-    private IList GetDoubleColumns(int statIdx) {
-      var column = (DoublePreprocessingDataColumn)Content.PreprocessingData.DataColumns[statIdx];
-      return new List<object> {
-        column.GetValueType().Name,
-        column.GetNumberOfMissingValues(),
-        column.GetMin(),
-        column.GetMax(),
-        column.GetMedian(),
-        column.GetMean(),
-        column.GetStandardDeviation(),
-        column.GetVariance(),
-        column.GetQuantile(0.25),
-        column.GetQuantile(0.75),
-        column.GetMode(),
-        column.GetDistinctValues()
+    private List<string> GetDoubleColumns(int statIdx) {
+      var data = Content.PreprocessingData;
+      return new List<string> {
+        data.GetVariableType(statIdx).Name,
+        data.GetMissingValueCount(statIdx).ToString(),
+        data.GetMin<double>(statIdx, emptyValue: double.NaN).ToString(),
+        data.GetMax<double>(statIdx, emptyValue: double.NaN).ToString(),
+        data.GetMedian<double>(statIdx, emptyValue: double.NaN).ToString(),
+        data.GetMean<double>(statIdx, emptyValue: double.NaN).ToString(),
+        data.GetStandardDeviation<double>(statIdx, emptyValue: double.NaN).ToString(),
+        data.GetVariance<double>(statIdx, emptyValue: double.NaN).ToString(),
+        data.GetQuantile<double>(0.25, statIdx, emptyValue: double.NaN).ToString(),
+        data.GetQuantile<double>(0.75, statIdx, emptyValue: double.NaN).ToString(),
+        data.GetMode<double>(statIdx, emptyValue: double.NaN).ToString(),
+        data.GetDistinctValues<double>(statIdx).ToString()
       };
     }
 
-    private IList GetStringColumns(int statIdx) {
-      var column = (StringPreprocessingDataColumn)Content.PreprocessingData.DataColumns[statIdx];
-      return new List<object> {
-        column.GetValueType().Name,
-        column.GetNumberOfMissingValues(),
-        "", //min
-        "", //max
-        "", //median
+    private List<string> GetStringColumns(int statIdx) {
+      var data = Content.PreprocessingData;
+      return new List<string> {
+        data.GetVariableType(statIdx).Name,
+        data.GetMissingValueCount(statIdx).ToString(),
+        "", // data.GetMin<string>(statIdx, emptyValue: string.Empty), //min
+        "", // data.GetMax<string>(statIdx, emptyValue: string.Empty), //max
+        "", // data.GetMedian<string>(statIdx, emptyValue: string.Empty), //median
         "", //average
         "", //standard deviation
         "", //variance
-        "", //quarter percentile
-        "", //three quarter percentile
-        column.GetMode(),
-        column.GetDistinctValues()
+        "", // data.GetQuantile<string>(0.25, statIdx, emptyValue: string.Empty), //quarter percentile
+        "", // data.GetQuantile<string>(0.75, statIdx, emptyValue: string.Empty), //three quarter percentile
+        data.GetMode<string>(statIdx, emptyValue: string.Empty),
+        data.GetDistinctValues<string>(statIdx).ToString()
       };
     }
 
-    private IList GetDateTimeColumns(int statIdx) {
-      var column = (DateTimePreprocessingDataColumn)Content.PreprocessingData.DataColumns[statIdx];
-      return new List<object> {
-        column.GetValueType().Name,
-        column.GetNumberOfMissingValues(),
-        column.GetMin(),
-        column.GetMax(),
-        column.GetMedian(),
-        column.GetMean(),
-        column.GetStandardDeviation(),  
-        /*column.GetVariance()*/"", // variance (in ticks) is usually to high to display a valid TimeSpan or DateTime
-        column.GetQuantile(0.25),
-        column.GetQuantile(0.75),
-        column.GetMode(),
-        column.GetDistinctValues()
+    private List<string> GetDateTimeColumns(int statIdx) {
+      var data = Content.PreprocessingData;
+      return new List<string> {
+        data.GetVariableType(statIdx).Name,
+        data.GetMissingValueCount(statIdx).ToString(),
+        data.GetMin<DateTime>(statIdx).ToString(),
+        data.GetMax<DateTime>(statIdx).ToString(),
+        data.GetMedian<DateTime>(statIdx).ToString(),
+        data.GetMean<DateTime>(statIdx).ToString(),
+        "", // should be of type TimeSpan //data.GetStandardDeviation<DateTime>(statIdx).ToString(),
+        "", // should be of type TimeSpan //data.GetVariance<DateTime>(statIdx).ToString(),
+        data.GetQuantile<DateTime>(0.25, statIdx).ToString(),
+        data.GetQuantile<DateTime>(0.75, statIdx).ToString(),
+        data.GetMode<DateTime>(statIdx).ToString(),
+        data.GetDistinctValues<DateTime>(statIdx).ToString()
       };
     }
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/DataGridContent.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/DataGridContent.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/DataGridContent.cs	(revision 15431)
@@ -90,5 +90,5 @@
 
     public void DeleteRows(IEnumerable<int> rows) {
-      PreprocessingData.DeleteRows(rows);
+      PreprocessingData.DeleteRowsWithIndices(rows);
     }
 
@@ -134,79 +134,80 @@
 
     #region Manipulations
+    private void ReplaceIndicesByValue(IDictionary<int, IList<int>> cells, Func<int, double> doubleAggregator = null,
+      Func<int, DateTime> dateTimeAggregator = null, Func<int, string> stringAggregator = null) {
+      PreprocessingData.InTransaction(() => {
+        foreach (var column in cells) {
+          if (doubleAggregator != null && PreprocessingData.VariableHasType<double>(column.Key)) {
+            var value = doubleAggregator(column.Key);
+            foreach (int index in column.Value)
+              PreprocessingData.SetCell<double>(column.Key, index, value);
+          } else if (dateTimeAggregator != null && PreprocessingData.VariableHasType<DateTime>(column.Key)) {
+            var value = dateTimeAggregator(column.Key);
+            foreach (int index in column.Value)
+              PreprocessingData.SetCell<DateTime>(column.Key, index, value);
+          } else if (stringAggregator != null && PreprocessingData.VariableHasType<string>(column.Key)) {
+            var value = stringAggregator(column.Key);
+            foreach (int index in column.Value)
+              PreprocessingData.SetCell<string>(column.Key, index, value);
+          }
+        }
+      });
+    }
+
+    private void ReplaceIndicesByValues(IDictionary<int, IList<int>> cells, Func<int, IEnumerable<double>> doubleAggregator = null,
+      Func<int, IEnumerable<DateTime>> dateTimeAggregator = null, Func<int, IEnumerable<string>> stringAggregator = null) {
+      PreprocessingData.InTransaction(() => {
+        foreach (var column in cells) {
+          if (doubleAggregator != null && PreprocessingData.VariableHasType<double>(column.Key)) {
+            var values = doubleAggregator(column.Key);
+            foreach (var pair in column.Value.Zip(values, (row, value) => new { row, value }))
+              PreprocessingData.SetCell<double>(column.Key, pair.row, pair.value);
+          } else if (dateTimeAggregator != null && PreprocessingData.VariableHasType<DateTime>(column.Key)) {
+            var values = dateTimeAggregator(column.Key);
+            foreach (var pair in column.Value.Zip(values, (row, value) => new { row, value }))
+              PreprocessingData.SetCell<DateTime>(column.Key, pair.row, pair.value);
+          } else if (stringAggregator != null && PreprocessingData.VariableHasType<string>(column.Key)) {
+            var values = stringAggregator(column.Key);
+            foreach (var pair in column.Value.Zip(values, (row, value) => new { row, value }))
+              PreprocessingData.SetCell<string>(column.Key, pair.row, pair.value);
+          }
+        }
+      });
+    }
+
     public void ReplaceIndicesByMean(IDictionary<int, IList<int>> cells, bool considerSelection = false) {
-      PreprocessingData.InTransaction(() => {
-        foreach (var column in cells) {
-          PreprocessingData.DataColumns[column.Key].TypeSwitch(
-            c => {
-              var mean = c.GetMean(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = mean;
-            },
-            dateTimeAction: c => {
-              var mean = c.GetMean(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = mean;
-            });
-        }
-      });
+      ReplaceIndicesByValue(cells,
+        col => PreprocessingData.GetMean<double>(col, considerSelection),
+        col => PreprocessingData.GetMean<DateTime>(col, considerSelection));
     }
 
     public void ReplaceIndicesByMedianValue(IDictionary<int, IList<int>> cells, bool considerSelection = false) {
-      PreprocessingData.InTransaction(() => {
-        foreach (var column in cells) {
-          PreprocessingData.DataColumns[column.Key].TypeSwitch(
-            c => {
-              var median = c.GetMedian(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = median;
-            },
-            c => {
-              var median = c.GetMedian(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = median;
-            },
-            c => {
-              var median = c.GetMedian(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = median;
-            });
-        }
-      });
+      ReplaceIndicesByValue(cells,
+        col => PreprocessingData.GetMedian<double>(col, considerSelection),
+        col => PreprocessingData.GetMedian<DateTime>(col, considerSelection));
     }
 
     public void ReplaceIndicesByMode(IDictionary<int, IList<int>> cells, bool considerSelection = false) {
-      PreprocessingData.InTransaction(() => {
-        foreach (var column in cells) {
-          PreprocessingData.DataColumns[column.Key].TypeSwitch(
-            c => {
-              var mode = c.GetMode(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = mode;
-            },
-            c => {
-              var mode = c.GetMode(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = mode;
-            },
-            c => {
-              var mode = c.GetMode(considerSelection ? column.Value : null);
-              foreach (var index in column.Value) c[index] = mode;
-            });
-        }
-      });
+      ReplaceIndicesByValue(cells,
+        col => PreprocessingData.GetMode<double>(col, considerSelection),
+        col => PreprocessingData.GetMode<DateTime>(col, considerSelection),
+        col => PreprocessingData.GetMode<string>(col, considerSelection));
     }
 
     public void ReplaceIndicesByRandomValue(IDictionary<int, IList<int>> cells, bool considerSelection = false) {
       var rand = new FastRandom();
-      PreprocessingData.InTransaction(() => {
-        foreach (var column in cells) {
-          PreprocessingData.DataColumns[column.Key].TypeSwitch(
-            c => {
-              double min = c.GetMin(considerSelection ? column.Value : null);
-              double max = c.GetMax(considerSelection ? column.Value : null);
-              double range = max - min;
-              foreach (var index in column.Value) c[index] = min + rand.NextDouble() * range;
-            },
-            dateTimeAction: c => {
-              var min = c.GetMin(considerSelection ? column.Value : null);
-              var max = c.GetMax(considerSelection ? column.Value : null);
-              double range = (max - min).TotalSeconds;
-              foreach (var index in column.Value) c[index] = min + TimeSpan.FromSeconds(rand.NextDouble() * range);
-            });
-        }
-      });
+      ReplaceIndicesByValues(cells,
+        col => {
+          double min = PreprocessingData.GetMin<double>(col, considerSelection);
+          double max = PreprocessingData.GetMax<double>(col, considerSelection);
+          double range = max - min;
+          return cells[col].Select(_ => rand.NextDouble() * range + min);
+        },
+        col => {
+          var min = PreprocessingData.GetMin<DateTime>(col, considerSelection);
+          var max = PreprocessingData.GetMax<DateTime>(col, considerSelection);
+          double range = (max - min).TotalSeconds;
+          return cells[col].Select(_ => min + TimeSpan.FromSeconds(rand.NextDouble() * range));
+        });
     }
 
@@ -215,5 +216,5 @@
         foreach (var column in cells) {
           foreach (var rowIdx in column.Value) {
-            PreprocessingData.DataColumns[column.Key].SetValue(value, rowIdx);
+            PreprocessingData.SetValue(value, column.Key, rowIdx);
           }
         }
@@ -256,32 +257,41 @@
       int valuesToInterpolate = nextIndex - prevIndex;
 
-      PreprocessingData.DataColumns[column.Key].TypeSwitch(
-        c => {
-          double prev = c[prevIndex];
-          double next = c[nextIndex];
-          double interpolationStep = (next - prev) / valuesToInterpolate;
-          for (int i = prevIndex; i < nextIndex; i++) c[i] = prev + (interpolationStep * (i - prevIndex));
-        },
-        dateTimeAction: c => {
-          var prev = c[prevIndex];
-          var next = c[nextIndex];
-          double interpolationStep = (next - prev).TotalSeconds / valuesToInterpolate;
-          for (int i = prevIndex; i < nextIndex; i++) c[i] = prev.AddSeconds(interpolationStep * (i - prevIndex));
-        }
-      );
+      if (PreprocessingData.VariableHasType<double>(column.Key)) {
+        double prev = PreprocessingData.GetCell<double>(column.Key, prevIndex);
+        double next = PreprocessingData.GetCell<double>(column.Key, nextIndex);
+        double interpolationStep = (next - prev) / valuesToInterpolate;
+
+        for (int i = prevIndex; i < nextIndex; ++i) {
+          double interpolated = prev + (interpolationStep * (i - prevIndex));
+          PreprocessingData.SetCell<double>(column.Key, i, interpolated);
+        }
+      } else if (PreprocessingData.VariableHasType<DateTime>(column.Key)) {
+        DateTime prev = PreprocessingData.GetCell<DateTime>(column.Key, prevIndex);
+        DateTime next = PreprocessingData.GetCell<DateTime>(column.Key, nextIndex);
+        double interpolationStep = (next - prev).TotalSeconds / valuesToInterpolate;
+
+        for (int i = prevIndex; i < nextIndex; ++i) {
+          DateTime interpolated = prev.AddSeconds(interpolationStep * (i - prevIndex));
+          PreprocessingData.SetCell<DateTime>(column.Key, i, interpolated);
+        }
+      }
     }
 
     private int IndexOfPrevPresentValue(int columnIndex, int start) {
-      int index = start - 1;
-      while (index >= 0 && PreprocessingData.IsCellEmpty(columnIndex, index))
-        index--;
-      return index;
+      int offset = start - 1;
+      while (offset >= 0 && PreprocessingData.IsCellEmpty(columnIndex, offset)) {
+        offset--;
+      }
+
+      return offset;
     }
 
     private int IndexOfNextPresentValue(int columnIndex, int start) {
-      int index = start + 1;
-      while (index < PreprocessingData.Rows && PreprocessingData.IsCellEmpty(columnIndex, index))
-        index++;
-      return index;
+      int offset = start + 1;
+      while (offset < PreprocessingData.Rows && PreprocessingData.IsCellEmpty(columnIndex, offset)) {
+        offset++;
+      }
+
+      return offset;
     }
 
@@ -293,5 +303,5 @@
         PreprocessingData.InTransaction(() => {
           // process all given ranges - e.g. TrainingPartition, TestPartition
-          foreach (var range in ranges) {
+          foreach (IntRange range in ranges) {
             var indices = Enumerable.Range(0, PreprocessingData.Rows).ToArray();
             var shuffledIndices = Enumerable.Range(range.Start, range.Size).Shuffle(random).ToArray();
@@ -314,23 +324,23 @@
     public void ReOrderToIndices(int[] indices) {
       PreprocessingData.InTransaction(() => {
-        foreach (var column in PreprocessingData.DataColumns) {
-          column.TypeSwitch(
-            c => {
-              if (indices.Length != c.Values.Count) throw new InvalidOperationException("The number of provided indices does not match the values.");
-              var originalData = new List<double>(c.Values);
-              for (int i = 0; i < indices.Length; i++) c[i] = originalData[indices[i]];
-            },
-            c => {
-              if (indices.Length != c.Values.Count) throw new InvalidOperationException("The number of provided indices does not match the values.");
-              var originalData = new List<string>(c.Values);
-              for (int i = 0; i < indices.Length; i++) c[i] = originalData[indices[i]];
-            },
-            c => {
-              if (indices.Length != c.Values.Count) throw new InvalidOperationException("The number of provided indices does not match the values.");
-              var originalData = new List<DateTime>(c.Values);
-              for (int i = 0; i < indices.Length; i++) c[i] = originalData[indices[i]];
-            });
-        }
-      });
+        for (int i = 0; i < PreprocessingData.Columns; ++i) {
+          if (PreprocessingData.VariableHasType<double>(i))
+            ReOrderToIndices<double>(i, indices);
+          else if (PreprocessingData.VariableHasType<string>(i))
+            ReOrderToIndices<string>(i, indices);
+          else if (PreprocessingData.VariableHasType<DateTime>(i))
+            ReOrderToIndices<DateTime>(i, indices);
+        }
+      });
+    }
+
+    private void ReOrderToIndices<T>(int columnIndex, int[] indices) {
+      var originalData = new List<T>(PreprocessingData.GetValues<T>(columnIndex));
+      if (indices.Length != originalData.Count) throw new InvalidOperationException("The number of provided indices does not match the values.");
+
+      for (int i = 0; i < indices.Length; i++) {
+        T newValue = originalData[indices[i]];
+        PreprocessingData.SetCell<T>(columnIndex, i, newValue);
+      }
     }
     #endregion
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/ManipulationContent.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/ManipulationContent.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/ManipulationContent.cs	(revision 15431)
@@ -57,11 +57,8 @@
 
       for (int i = 0; i < PreprocessingData.Rows; ++i) {
-        int missingCount = 0;
-        for (var col = 0; col < PreprocessingData.DataColumns.Count; col++) {
-          if (!PreprocessingData.DataColumns[col].IsValidValue(i))
-            missingCount++;
+        int missingCount = PreprocessingData.GetRowMissingValueCount(i);
+        if (100f / PreprocessingData.Columns * missingCount > percent) {
+          rows.Add(i);
         }
-        if (100f / PreprocessingData.Columns * missingCount > percent)
-          rows.Add(i);
       }
 
@@ -72,5 +69,5 @@
       List<int> columns = new List<int>();
       for (int i = 0; i < PreprocessingData.Columns; ++i) {
-        int missingCount = PreprocessingData.DataColumns[i].GetNumberOfMissingValues();
+        int missingCount = PreprocessingData.GetMissingValueCount(i);
         if (100f / PreprocessingData.Rows * missingCount > percent) {
           columns.Add(i);
@@ -83,14 +80,17 @@
     public List<int> ColumnsWithVarianceSmaller(double variance) {
       List<int> columns = new List<int>();
-
-      for (int i = 0; i < PreprocessingData.Columns; i++) {
-        if (PreprocessingData.DataColumns[i].TypeSwitch<bool>(
-          c => c.GetVariance() < variance,
-          c => false,
-          c => c.GetVariance().Ticks / TimeSpan.TicksPerSecond < variance
-        ))
-          columns.Add(i);
+      for (int i = 0; i < PreprocessingData.Columns; ++i) {
+        if (PreprocessingData.VariableHasType<double>(i)) {
+          double columnVariance = PreprocessingData.GetVariance<double>(i);
+          if (columnVariance < variance) {
+            columns.Add(i);
+          }
+        } else if (PreprocessingData.VariableHasType<DateTime>(i)) {
+          double columnVariance = (double)PreprocessingData.GetVariance<DateTime>(i).Ticks / TimeSpan.TicksPerSecond;
+          if (columnVariance < variance) {
+            columns.Add(i);
+          }
+        }
       }
-
       return columns;
     }
@@ -119,5 +119,5 @@
       PreprocessingData.InTransaction(() => {
         foreach (int column in columns.OrderByDescending(x => x)) {
-          PreprocessingData.DataColumns.RemoveAt(column);
+          PreprocessingData.DeleteColumn(column);
         }
       });
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/PreprocessingChartContent.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/PreprocessingChartContent.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/PreprocessingChartContent.cs	(revision 15431)
@@ -82,5 +82,5 @@
 
     public static DataRow CreateDataRow(IFilteredPreprocessingData preprocessingData, string variableName, DataRowVisualProperties.DataRowChartType chartType) {
-      var values = preprocessingData.GetValues<double>(preprocessingData.GetColumnIndex(variableName));
+      IList<double> values = preprocessingData.GetValues<double>(preprocessingData.GetColumnIndex(variableName));
       DataRow row = new DataRow(variableName, "", values);
       row.VisualProperties.ChartType = chartType;
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/ScatterPlotContent.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/ScatterPlotContent.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Content/ScatterPlotContent.cs	(revision 15431)
@@ -21,4 +21,5 @@
 
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using HeuristicLab.Analysis;
@@ -50,10 +51,9 @@
     #endregion
 
-    public static ScatterPlot CreateScatterPlot(IFilteredPreprocessingData preprocessingData, string variableNameX, string variableNameY,
-      string variableNameGroup = "-", LegendOrder legendOrder = LegendOrder.Alphabetically) {
+    public static ScatterPlot CreateScatterPlot(IFilteredPreprocessingData preprocessingData, string variableNameX, string variableNameY, string variableNameGroup = "-", LegendOrder legendOrder = LegendOrder.Alphabetically) {
       ScatterPlot scatterPlot = new ScatterPlot();
 
-      var xValues = preprocessingData.GetValues<double>(preprocessingData.GetColumnIndex(variableNameX));
-      var yValues = preprocessingData.GetValues<double>(preprocessingData.GetColumnIndex(variableNameY));
+      IList<double> xValues = preprocessingData.GetValues<double>(preprocessingData.GetColumnIndex(variableNameX));
+      IList<double> yValues = preprocessingData.GetValues<double>(preprocessingData.GetColumnIndex(variableNameY));
 
       var points = xValues.Zip(yValues, (x, y) => new Point2D<double>(x, y)).ToList();
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/FilteredPreprocessingData.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/FilteredPreprocessingData.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/FilteredPreprocessingData.cs	(revision 15431)
@@ -38,8 +38,4 @@
     private IPreprocessingData filteredData;
 
-    public IList<PreprocessingDataColumn> DataColumns {
-      get { return ActiveData.DataColumns; }
-    }
-
     public IPreprocessingData ActiveData {
       get { return IsFiltered ? filteredData : originalData; }
@@ -86,9 +82,9 @@
     }
 
-    public IEnumerable<T> GetValues<T>(int columnIndex, bool considerSelection) {
+    public IList<T> GetValues<T>(int columnIndex, bool considerSelection) {
       return ActiveData.GetValues<T>(columnIndex, considerSelection);
     }
 
-    public void SetValues<T>(int columnIndex, IEnumerable<T> values) {
+    public void SetValues<T>(int columnIndex, IList<T> values) {
       if (IsFiltered)
         throw new InvalidOperationException("SetValues not possible while data is filtered");
@@ -127,9 +123,9 @@
     }
 
-    public void DeleteRows(IEnumerable<int> rows) {
+    public void DeleteRowsWithIndices(IEnumerable<int> rows) {
       if (IsFiltered)
         throw new InvalidOperationException("DeleteRowsWithIndices not possible while data is filtered");
 
-      originalData.DeleteRows(rows);
+      originalData.DeleteRowsWithIndices(rows);
     }
 
@@ -277,4 +273,44 @@
     public void EndTransaction() {
       originalData.EndTransaction();
+    }
+    #endregion
+
+    #region Statistics
+    public T GetMin<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      return ActiveData.GetMin<T>(columnIndex, considerSelection, emptyValue);
+    }
+    public T GetMax<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      return ActiveData.GetMax<T>(columnIndex, considerSelection, emptyValue);
+    }
+    public T GetMean<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      return ActiveData.GetMean<T>(columnIndex, considerSelection, emptyValue);
+    }
+    public T GetMedian<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T> {
+      return ActiveData.GetMean<T>(columnIndex, considerSelection, emptyValue);
+    }
+    public T GetMode<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IEquatable<T> {
+      return ActiveData.GetMode<T>(columnIndex, considerSelection, emptyValue);
+    }
+    public T GetStandardDeviation<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      return ActiveData.GetStandardDeviation<T>(columnIndex, considerSelection, emptyValue);
+    }
+    public T GetVariance<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      return ActiveData.GetVariance<T>(columnIndex, considerSelection, emptyValue);
+    }
+    public T GetQuantile<T>(double alpha, int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T> {
+      return ActiveData.GetQuantile<T>(alpha, columnIndex, considerSelection, emptyValue);
+    }
+    public int GetDistinctValues<T>(int columnIndex, bool considerSelection = false) {
+      return ActiveData.GetDistinctValues<T>(columnIndex, considerSelection);
+    }
+
+    public int GetMissingValueCount() {
+      return ActiveData.GetMissingValueCount();
+    }
+    public int GetMissingValueCount(int columnIndex) {
+      return ActiveData.GetMissingValueCount(columnIndex);
+    }
+    public int GetRowMissingValueCount(int rowIndex) {
+      return ActiveData.GetRowMissingValueCount(rowIndex);
     }
     #endregion
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/IPreprocessingData.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/IPreprocessingData.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/IPreprocessingData.cs	(revision 15431)
@@ -28,7 +28,4 @@
 namespace HeuristicLab.DataPreprocessing {
   public interface IPreprocessingData : INamedItem {
-
-    IList<PreprocessingDataColumn> DataColumns { get; }
-
     #region Cells
     bool IsCellEmpty(int columnIndex, int rowIndex);
@@ -39,7 +36,7 @@
     string GetCellAsString(int columnIndex, int rowIndex);
 
-    IEnumerable<T> GetValues<T>(int columnIndex, bool considerSelection = false);
+    IList<T> GetValues<T>(int columnIndex, bool considerSelection = false);
 
-    void SetValues<T>(int columnIndex, IEnumerable<T> values);
+    void SetValues<T>(int columnIndex, IList<T> values);
     bool SetValue(string value, int columnIndex, int rowIndex);
 
@@ -51,5 +48,5 @@
     void InsertRow(int rowIndex);
     void DeleteRow(int rowIndex);
-    void DeleteRows(IEnumerable<int> rows);
+    void DeleteRowsWithIndices(IEnumerable<int> rows);
     void InsertColumn<T>(string variableName, int columnIndex);
 
@@ -109,4 +106,20 @@
     void EndTransaction();
     #endregion
+
+    #region Statistics
+    T GetMin<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T));
+    T GetMax<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T));
+    T GetMean<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T));
+    T GetMedian<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T>;
+    T GetMode<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IEquatable<T>;
+    T GetStandardDeviation<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T));
+    T GetVariance<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T));
+    T GetQuantile<T>(double alpha, int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T>;
+    int GetDistinctValues<T>(int columnIndex, bool considerSelection = false);
+
+    int GetMissingValueCount();
+    int GetMissingValueCount(int columnIndex);
+    int GetRowMissingValueCount(int rowIndex);
+    #endregion
   }
 }
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/PreprocessingData.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/PreprocessingData.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/Data/PreprocessingData.cs	(revision 15431)
@@ -32,14 +32,13 @@
 
 namespace HeuristicLab.DataPreprocessing {
+
   [Item("PreprocessingData", "Represents data used for preprocessing.")]
   [StorableClass]
   public class PreprocessingData : NamedItem, IPreprocessingData {
 
-    [Storable] private List<PreprocessingDataColumn> dataColumns;
-
-    public IList<PreprocessingDataColumn> DataColumns {
-      get { return dataColumns; }
-    }
-
+    [Storable]
+    protected IList<IList> variableValues;
+    [Storable]
+    protected IList<string> variableNames;
 
     #region Constructor, Cloning & Persistence
@@ -48,5 +47,4 @@
       Name = "Preprocessing Data";
 
-      dataColumns = new List<PreprocessingDataColumn>();
       Transformations = new List<ITransformation>();
       selection = new Dictionary<int, IList<int>>();
@@ -59,7 +57,8 @@
     protected PreprocessingData(PreprocessingData original, Cloner cloner)
       : base(original, cloner) {
-      dataColumns = new List<PreprocessingDataColumn>(original.dataColumns.Select(cloner.Clone));
-      TrainingPartition = cloner.Clone(original.TrainingPartition);
-      TestPartition = cloner.Clone(original.TestPartition);
+      variableValues = CopyVariableValues(original.variableValues);
+      variableNames = new List<string>(original.variableNames);
+      TrainingPartition = (IntRange)original.TrainingPartition.Clone(cloner);
+      TestPartition = (IntRange)original.TestPartition.Clone(cloner);
       Transformations = new List<ITransformation>(original.Transformations.Select(cloner.Clone));
 
@@ -100,12 +99,10 @@
     #region Cells
     public bool IsCellEmpty(int columnIndex, int rowIndex) {
-      return !dataColumns[columnIndex].IsValidValue(rowIndex);
+      var value = variableValues[columnIndex][rowIndex];
+      return IsMissingValue(value);
     }
 
     public T GetCell<T>(int columnIndex, int rowIndex) {
-      return dataColumns[columnIndex].TypeSwitch<T>(
-        c => c[rowIndex],
-        c => c[rowIndex],
-        c => c[rowIndex]);
+      return (T)variableValues[columnIndex][rowIndex];
     }
 
@@ -118,9 +115,5 @@
         InsertColumn<T>(i.ToString(), i);
 
-      dataColumns[columnIndex].TypeSwitch<T>(value,
-        (c, v) => c[rowIndex] = v,
-        (c, v) => c[rowIndex] = v,
-        (c, v) => c[rowIndex] = v);
-
+      variableValues[columnIndex][rowIndex] = value;
       if (!IsInTransaction)
         OnChanged(DataPreprocessingChangedEventType.ChangeItem, columnIndex, rowIndex);
@@ -128,50 +121,74 @@
 
     public string GetCellAsString(int columnIndex, int rowIndex) {
-      return dataColumns[columnIndex].GetValue(rowIndex);
-    }
-
-    public IEnumerable<T> GetValues<T>(int columnIndex, bool considerSelection) {
-      return dataColumns[columnIndex].TypeSwitch<T>(
-        c => c.GetValues(considerSelection ? selection[columnIndex] : null),
-        c => c.GetValues(considerSelection ? selection[columnIndex] : null),
-        c => c.GetValues(considerSelection ? selection[columnIndex] : null));
-    }
-
-    public void SetValues<T>(int columnIndex, IEnumerable<T> values) {
+      return variableValues[columnIndex][rowIndex].ToString();
+    }
+
+    public IList<T> GetValues<T>(int columnIndex, bool considerSelection) {
+      if (considerSelection) {
+        var list = new List<T>();
+        foreach (var rowIdx in selection[columnIndex]) {
+          list.Add((T)variableValues[columnIndex][rowIdx]);
+        }
+        return list;
+      } else {
+        return (IList<T>)variableValues[columnIndex];
+      }
+    }
+
+    public void SetValues<T>(int columnIndex, IList<T> values) {
       SaveSnapshot(DataPreprocessingChangedEventType.ChangeColumn, columnIndex, -1);
       if (VariableHasType<T>(columnIndex)) {
-        var name = dataColumns[columnIndex].Name;
-        if (dataColumns[columnIndex].IsType<double>()) {
-          dataColumns[columnIndex] = new DoublePreprocessingDataColumn(name, (IEnumerable<double>)values);
-        } else if (dataColumns[columnIndex].IsType<string>()) {
-          dataColumns[columnIndex] = new StringPreprocessingDataColumn(name, (IEnumerable<string>)values);
-        } else if (dataColumns[columnIndex].IsType<DateTime>()) {
-          dataColumns[columnIndex] = new DateTimePreprocessingDataColumn(name, (IEnumerable<DateTime>)values);
+        variableValues[columnIndex] = (IList)values;
+      } else {
+        throw new ArgumentException("The datatype of column " + columnIndex + " must be of type " + variableValues[columnIndex].GetType().Name + " but was " + typeof(T).Name);
+      }
+      if (!IsInTransaction)
+        OnChanged(DataPreprocessingChangedEventType.ChangeColumn, columnIndex, -1);
+    }
+
+    public bool SetValue(string value, int columnIndex, int rowIndex) {
+      bool valid = false;
+      if (VariableHasType<double>(columnIndex)) {
+        double val;
+        if (string.IsNullOrWhiteSpace(value)) {
+          val = double.NaN;
+          valid = true;
         } else {
-          throw new ArgumentException("Unknown column type");
-        }
+          valid = double.TryParse(value, out val);
+        }
+        if (valid)
+          SetCell(columnIndex, rowIndex, val);
+      } else if (VariableHasType<string>(columnIndex)) {
+        valid = value != null;
+        if (valid)
+          SetCell(columnIndex, rowIndex, value);
+      } else if (VariableHasType<DateTime>(columnIndex)) {
+        DateTime date;
+        valid = DateTime.TryParse(value, out date);
+        if (valid)
+          SetCell(columnIndex, rowIndex, date);
       } else {
-        throw new ArgumentException("The datatype of column " + columnIndex + " must be of type " + dataColumns[columnIndex].GetType().Name + " but was " + typeof(T).Name);
-      }
+        throw new ArgumentException("column " + columnIndex + " contains a non supported type.");
+      }
+
       if (!IsInTransaction)
         OnChanged(DataPreprocessingChangedEventType.ChangeColumn, columnIndex, -1);
-    }
-
-    public bool SetValue(string value, int columnIndex, int rowIndex) {
-      var column = dataColumns[columnIndex];
-      bool successful = column.SetValue(value, rowIndex);
-
-      if (!IsInTransaction)
-        OnChanged(DataPreprocessingChangedEventType.ChangeColumn, columnIndex, -1);
-
-      return successful;
+
+      return valid;
     }
 
     public int Columns {
-      get { return dataColumns.Count; }
+      get { return variableNames.Count; }
     }
 
     public int Rows {
-      get { return dataColumns.Any() ? dataColumns.Max(c => c.Length) : 0; }
+      get { return variableValues.Count > 0 ? variableValues[0].Count : 0; }
+    }
+
+    public static bool IsMissingValue(object value) {
+      if (value is double) return double.IsNaN((double)value);
+      if (value is string) return string.IsNullOrEmpty((string)value);
+      if (value is DateTime) return ((DateTime)value).Equals(DateTime.MinValue);
+      throw new ArgumentException();
     }
     #endregion
@@ -180,12 +197,8 @@
     public void InsertRow(int rowIndex) {
       SaveSnapshot(DataPreprocessingChangedEventType.DeleteRow, -1, rowIndex);
-
-      foreach (var column in dataColumns) {
-        column.TypeSwitch(
-          c => c.Values.Insert(rowIndex, double.NaN),
-          c => c.Values.Insert(rowIndex, null),
-          c => c.Values.Insert(rowIndex, DateTime.MinValue));
-      }
-
+      foreach (IList column in variableValues) {
+        Type type = column.GetType().GetGenericArguments()[0];
+        column.Insert(rowIndex, type.IsValueType ? Activator.CreateInstance(type) : null);
+      }
       if (TrainingPartition.Start <= rowIndex && rowIndex <= TrainingPartition.End) {
         TrainingPartition.End++;
@@ -201,23 +214,34 @@
         }
       }
-
       if (!IsInTransaction)
         OnChanged(DataPreprocessingChangedEventType.AddRow, -1, rowIndex);
     }
-
     public void DeleteRow(int rowIndex) {
-      DeleteRows(new[] { rowIndex });
-    }
-    public void DeleteRows(IEnumerable<int> rowIndices) {
+      SaveSnapshot(DataPreprocessingChangedEventType.AddRow, -1, rowIndex);
+      foreach (IList column in variableValues) {
+        column.RemoveAt(rowIndex);
+      }
+      if (TrainingPartition.Start <= rowIndex && rowIndex <= TrainingPartition.End) {
+        TrainingPartition.End--;
+        if (TrainingPartition.End <= TestPartition.Start) {
+          TestPartition.Start--;
+          TestPartition.End--;
+        }
+      } else if (TestPartition.Start <= rowIndex && rowIndex <= TestPartition.End) {
+        TestPartition.End--;
+        if (TestPartition.End <= TrainingPartition.Start) {
+          TestPartition.Start--;
+          TestPartition.End--;
+        }
+      }
+      if (!IsInTransaction)
+        OnChanged(DataPreprocessingChangedEventType.DeleteRow, -1, rowIndex);
+    }
+    public void DeleteRowsWithIndices(IEnumerable<int> rows) {
       SaveSnapshot(DataPreprocessingChangedEventType.AddRow, -1, -1);
-
-      foreach (int rowIndex in rowIndices.OrderByDescending(x => x)) {
-        foreach (var column in dataColumns) {
-          column.TypeSwitch(
-            c => c.Values.RemoveAt(rowIndex),
-            c => c.Values.RemoveAt(rowIndex),
-            c => c.Values.RemoveAt(rowIndex));
-        }
-
+      foreach (int rowIndex in rows.OrderByDescending(x => x)) {
+        foreach (IList column in variableValues) {
+          column.RemoveAt(rowIndex);
+        }
         if (TrainingPartition.Start <= rowIndex && rowIndex <= TrainingPartition.End) {
           TrainingPartition.End--;
@@ -234,5 +258,4 @@
         }
       }
-
       if (!IsInTransaction)
         OnChanged(DataPreprocessingChangedEventType.DeleteRow, -1, -1);
@@ -241,15 +264,6 @@
     public void InsertColumn<T>(string variableName, int columnIndex) {
       SaveSnapshot(DataPreprocessingChangedEventType.DeleteColumn, columnIndex, -1);
-
-      if (typeof(T) == typeof(double)) {
-        dataColumns.Insert(columnIndex, new DoublePreprocessingDataColumn(variableName, Enumerable.Repeat<double>(double.NaN, Rows)));
-      } else if (typeof(T) == typeof(string)) {
-        dataColumns.Insert(columnIndex, new StringPreprocessingDataColumn(variableName, Enumerable.Repeat<string>(string.Empty, Rows)));
-      } else if (typeof(T) == typeof(DateTime)) {
-        dataColumns.Insert(columnIndex, new DateTimePreprocessingDataColumn(variableName, Enumerable.Repeat<DateTime>(DateTime.MinValue, Rows)));
-      } else {
-        throw new ArgumentException("The datatype of column " + variableName + " must be of type double, string or DateTime");
-      }
-
+      variableValues.Insert(columnIndex, new List<T>(Enumerable.Repeat(default(T), Rows)));
+      variableNames.Insert(columnIndex, variableName);
       if (!IsInTransaction)
         OnChanged(DataPreprocessingChangedEventType.AddColumn, columnIndex, -1);
@@ -258,7 +272,6 @@
     public void DeleteColumn(int columnIndex) {
       SaveSnapshot(DataPreprocessingChangedEventType.AddColumn, columnIndex, -1);
-
-      dataColumns.RemoveAt(columnIndex);
-
+      variableValues.RemoveAt(columnIndex);
+      variableNames.RemoveAt(columnIndex);
       if (!IsInTransaction)
         OnChanged(DataPreprocessingChangedEventType.DeleteColumn, columnIndex, -1);
@@ -266,10 +279,8 @@
 
     public void RenameColumn(int columnIndex, string name) {
-      if (columnIndex < 0 || columnIndex > dataColumns.Count)
+      SaveSnapshot(DataPreprocessingChangedEventType.ChangeColumn, columnIndex, -1);
+      if (columnIndex < 0 || columnIndex > variableNames.Count)
         throw new ArgumentOutOfRangeException("columnIndex");
-
-      SaveSnapshot(DataPreprocessingChangedEventType.ChangeColumn, columnIndex, -1);
-
-      dataColumns[columnIndex].Name = name;
+      variableNames[columnIndex] = name;
 
       if (!IsInTransaction)
@@ -279,10 +290,9 @@
     public void RenameColumns(IList<string> names) {
       if (names == null) throw new ArgumentNullException("names");
-      if (names.Count != dataColumns.Count) throw new ArgumentException("number of names must match the number of columns.", "names");
+      if (names.Count != variableNames.Count) throw new ArgumentException("number of names must match the number of columns.", "names");
 
       SaveSnapshot(DataPreprocessingChangedEventType.ChangeColumn, -1, -1);
-
       for (int i = 0; i < names.Count; i++)
-        dataColumns[i].Name = names[i];
+        variableNames[i] = names[i];
 
       if (!IsInTransaction)
@@ -291,5 +301,5 @@
 
     public bool AreAllStringColumns(IEnumerable<int> columnIndices) {
-      return columnIndices.All(VariableHasType<string>);
+      return columnIndices.All(x => VariableHasType<string>(x));
     }
     #endregion
@@ -297,25 +307,32 @@
     #region Variables
     public IEnumerable<string> VariableNames {
-      get { return dataColumns.Select(c => c.Name); }
+      get { return variableNames; }
     }
 
     public IEnumerable<string> GetDoubleVariableNames() {
-      return dataColumns.OfType<DoublePreprocessingDataColumn>().Select(c => c.Name);
+      var doubleVariableNames = new List<string>();
+      for (int i = 0; i < Columns; ++i) {
+        if (VariableHasType<double>(i)) {
+          doubleVariableNames.Add(variableNames[i]);
+        }
+      }
+      return doubleVariableNames;
     }
 
     public string GetVariableName(int columnIndex) {
-      return dataColumns[columnIndex].Name;
+      return variableNames[columnIndex];
     }
 
     public int GetColumnIndex(string variableName) {
-      return dataColumns.FindIndex(c => c.Name == variableName);
+      return variableNames.IndexOf(variableName);
     }
 
     public bool VariableHasType<T>(int columnIndex) {
-      return dataColumns[columnIndex].IsType<T>();
+      return columnIndex >= variableValues.Count || variableValues[columnIndex] is List<T>;
     }
 
     public Type GetVariableType(int columnIndex) {
-      return dataColumns[columnIndex].GetValueType();
+      var listType = variableValues[columnIndex].GetType();
+      return listType.GenericTypeArguments.Single();
     }
 
@@ -375,21 +392,24 @@
     #region Import & Export
     public void Import(IDataAnalysisProblemData problemData) {
-      var dataset = problemData.Dataset;
+      Dataset dataset = (Dataset)problemData.Dataset;
+      variableNames = new List<string>(problemData.Dataset.VariableNames);
       InputVariables = new List<string>(problemData.AllowedInputVariables);
-      TargetVariable = problemData is IRegressionProblemData ? ((IRegressionProblemData)problemData).TargetVariable
-        : problemData is IClassificationProblemData ? ((IClassificationProblemData)problemData).TargetVariable
-        : null;
-
-      dataColumns.Clear();
+      TargetVariable = (problemData is IRegressionProblemData) ? ((IRegressionProblemData)problemData).TargetVariable
+        : (problemData is IClassificationProblemData) ? ((IClassificationProblemData)problemData).TargetVariable
+          : null;
+
+      int columnIndex = 0;
+      variableValues = new List<IList>();
       foreach (var variableName in problemData.Dataset.VariableNames) {
         if (dataset.VariableHasType<double>(variableName)) {
-          dataColumns.Add(new DoublePreprocessingDataColumn(variableName, dataset.GetDoubleValues(variableName)));
+          variableValues.Insert(columnIndex, dataset.GetDoubleValues(variableName).ToList());
         } else if (dataset.VariableHasType<string>(variableName)) {
-          dataColumns.Add(new StringPreprocessingDataColumn(variableName, dataset.GetStringValues(variableName)));
+          variableValues.Insert(columnIndex, dataset.GetStringValues(variableName).ToList());
         } else if (dataset.VariableHasType<DateTime>(variableName)) {
-          dataColumns.Add(new DateTimePreprocessingDataColumn(variableName, dataset.GetDateTimeValues(variableName)));
+          variableValues.Insert(columnIndex, dataset.GetDateTimeValues(variableName).ToList());
         } else {
           throw new ArgumentException("The datatype of column " + variableName + " must be of type double, string or DateTime");
         }
+        ++columnIndex;
       }
 
@@ -401,15 +421,10 @@
       IList<IList> values = new List<IList>();
 
-      for (int i = 0; i < Columns; i++) {
-        var doubleColumn = dataColumns[i] as DoublePreprocessingDataColumn;
-        var stringColumn = dataColumns[i] as StringPreprocessingDataColumn;
-        var dateTimeColumn = dataColumns[i] as DateTimePreprocessingDataColumn;
-        if (doubleColumn != null) values.Add(new List<double>(doubleColumn.GetValues()));
-        else if (stringColumn != null) values.Add(new List<string>(stringColumn.GetValues()));
-        else if (dateTimeColumn != null) values.Add(new List<DateTime>(dateTimeColumn.GetValues()));
-        else throw new InvalidOperationException("Column type not supported for export");
-      }
-
-      return new Dataset(VariableNames, values);
+      for (int i = 0; i < Columns; ++i) {
+        values.Add(variableValues[i]);
+      }
+
+      var dataset = new Dataset(variableNames, values);
+      return dataset;
     }
     #endregion
@@ -437,7 +452,8 @@
 
     #region Transactions
-    // Snapshot/History are not storable/cloneable on purpose
+    // Stapshot/History are nost storable/cloneable on purpose
     private class Snapshot {
-      public List<PreprocessingDataColumn> DataColumns { get; set; }
+      public IList<IList> VariableValues { get; set; }
+      public IList<string> VariableNames { get; set; }
 
       public IntRange TrainingPartition { get; set; }
@@ -456,5 +472,5 @@
     }
 
-    private const int MaxUndoDepth = 5;
+    private const int MAX_UNDO_DEPTH = 5;
 
     private readonly IList<Snapshot> undoHistory = new List<Snapshot>();
@@ -466,7 +482,7 @@
       if (IsInTransaction) return;
 
-      var cloner = new Cloner();
       var currentSnapshot = new Snapshot {
-        DataColumns = new List<PreprocessingDataColumn>(dataColumns.Select(cloner.Clone)),
+        VariableValues = CopyVariableValues(variableValues),
+        VariableNames = new List<string>(variableNames),
         TrainingPartition = new IntRange(TrainingPartition.Start, TrainingPartition.End),
         TestPartition = new IntRange(TestPartition.Start, TestPartition.End),
@@ -477,5 +493,5 @@
       };
 
-      if (undoHistory.Count >= MaxUndoDepth)
+      if (undoHistory.Count >= MAX_UNDO_DEPTH)
         undoHistory.RemoveAt(0);
 
@@ -490,5 +506,6 @@
       if (IsUndoAvailable) {
         Snapshot previousSnapshot = undoHistory[undoHistory.Count - 1];
-        dataColumns = previousSnapshot.DataColumns;
+        variableValues = previousSnapshot.VariableValues;
+        variableNames = previousSnapshot.VariableNames;
         TrainingPartition = previousSnapshot.TrainingPartition;
         TestPartition = previousSnapshot.TestPartition;
@@ -521,131 +538,128 @@
     #endregion
 
-    /* #region Statistics
-     public T GetMin<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
-       try {
-         return dataColumns[columnIndex].TypeSwitch<T>(
-           col => col.GetMin(considerSelection ? Selection[columnIndex] : null),
-           col => col.GetMin(considerSelection ? Selection[columnIndex] : null),
-           col => col.GetMin(considerSelection ? Selection[columnIndex] : null));
-       } catch (InvalidOperationException) {
-         return emptyValue;
-       }
-     }
-
-     public T GetMax<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
-       var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
-       return values.Any() ? values.Max() : emptyValue;
-     }
-
-     public T GetMean<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
-       return 
-
-
-       if (typeof(T) == typeof(double)) {
-         var values = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
-         return values.Any() ? Convert<T>(values.Average()) : emptyValue;
-       }
-       if (typeof(T) == typeof(string)) {
-         return Convert<T>(string.Empty);
-       }
-       if (typeof(T) == typeof(DateTime)) {
-         var values = GetValuesWithoutMissingValues<DateTime>(columnIndex, considerSelection);
-         return values.Any() ? Convert<T>(AggregateAsDouble(values, Enumerable.Average)) : emptyValue;
-       }
-
-       throw new InvalidOperationException(typeof(T) + " not supported");
-     }
-
-     public T GetMedian<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T> {
-       if (typeof(T) == typeof(double)) {// IEnumerable<double> is faster  
-         var doubleValues = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
-         return doubleValues.Any() ? Convert<T>(doubleValues.Median()) : emptyValue;
-       }
-       var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
-       return values.Any() ? values.Quantile(0.5) : emptyValue;
-     }
-
-     public T GetMode<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IEquatable<T> {
-       var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
-       return values.Any() ? values.GroupBy(x => x).OrderByDescending(g => g.Count()).Select(g => g.Key).First() : emptyValue;
-     }
-
-     public T GetStandardDeviation<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
-       if (typeof(T) == typeof(double)) {
-         var values = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
-         return values.Any() ? Convert<T>(values.StandardDeviation()) : emptyValue;
-       }
-       // For DateTime, std.dev / variance would have to be TimeSpan
-       //if (typeof(T) == typeof(DateTime)) {
-       //  var values = GetValuesWithoutMissingValues<DateTime>(columnIndex, considerSelection);
-       //  return values.Any() ? Convert<T>(AggregateAsDouble(values, EnumerableStatisticExtensions.StandardDeviation)) : emptyValue;
-       //}
-       return default(T);
-     }
-
-     public T GetVariance<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
-       if (typeof(T) == typeof(double)) {
-         var values = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
-         return values.Any() ? Convert<T>(values.Variance()) : emptyValue;
-       }
-       // DateTime variance often overflows long, thus the corresponding DateTime is invalid
-       //if (typeof(T) == typeof(DateTime)) {
-       //  var values = GetValuesWithoutMissingValues<DateTime>(columnIndex, considerSelection);
-       //  return values.Any() ? Convert<T>(AggregateAsDouble(values, EnumerableStatisticExtensions.Variance)) : emptyValue;
-       //}
-       return default(T);
-     }
-
-     public T GetQuantile<T>(double alpha, int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T> {
-       if (typeof(T) == typeof(double)) {// IEnumerable<double> is faster  
-         var doubleValues = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
-         return doubleValues.Any() ? Convert<T>(doubleValues.Quantile(alpha)) : emptyValue;
-       }
-       var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
-       return values.Any() ? values.Quantile(alpha) : emptyValue;
-     }
-
-     public int GetDistinctValues<T>(int columnIndex, bool considerSelection = false) {
-       var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
-       return values.GroupBy(x => x).Count();
-     }
-
-     private IEnumerable<T> GetValuesWithoutMissingValues<T>(int columnIndex, bool considerSelection) {
-       return GetValues<T>(columnIndex, considerSelection).Where(x =>
-         ColumnTypeSwitch<T, bool>(dataColumns[columnIndex], x,
-           (c, v) => c.IsValidValue(v),
-           (c, v) => c.IsValidValue(v),
-           (c, v) => c.IsValidValue(v)
-       ));
-     }
-
-     private static DateTime AggregateAsDouble(IEnumerable<DateTime> values, Func<IEnumerable<double>, double> func) {
-       return new DateTime((long)(func(values.Select(x => (double)x.Ticks / TimeSpan.TicksPerSecond)) * TimeSpan.TicksPerSecond));
-     }
-
-     public int GetMissingValueCount() {
-       int count = 0;
-       for (int i = 0; i < Columns; ++i) {
-         count += GetMissingValueCount(i);
-       }
-       return count;
-     }
-     public int GetMissingValueCount(int columnIndex) {
-       int sum = 0;
-       for (int i = 0; i < Rows; i++) {
-         if (IsCellEmpty(columnIndex, i))
-           sum++;
-       }
-       return sum;
-     }
-     public int GetRowMissingValueCount(int rowIndex) {
-       int sum = 0;
-       for (int i = 0; i < Columns; i++) {
-         if (IsCellEmpty(i, rowIndex))
-           sum++;
-       }
-       return sum;
-     }
-     #endregion  */
+    #region Statistics
+    public T GetMin<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
+      return values.Any() ? values.Min() : emptyValue;
+    }
+
+    public T GetMax<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
+      return values.Any() ? values.Max() : emptyValue;
+    }
+
+    public T GetMean<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      if (typeof(T) == typeof(double)) {
+        var values = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
+        return values.Any() ? Convert<T>(values.Average()) : emptyValue;
+      }
+      if (typeof(T) == typeof(string)) {
+        return Convert<T>(string.Empty);
+      }
+      if (typeof(T) == typeof(DateTime)) {
+        var values = GetValuesWithoutMissingValues<DateTime>(columnIndex, considerSelection);
+        return values.Any() ? Convert<T>(AggregateAsDouble(values, Enumerable.Average)) : emptyValue;
+      }
+
+      throw new InvalidOperationException(typeof(T) + " not supported");
+    }
+
+    public T GetMedian<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T> {
+      if (typeof(T) == typeof(double)) {// IEnumerable<double> is faster  
+        var doubleValues = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
+        return doubleValues.Any() ? Convert<T>(doubleValues.Median()) : emptyValue;
+      }
+      var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
+      return values.Any() ? values.Quantile(0.5) : emptyValue;
+    }
+
+    public T GetMode<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IEquatable<T> {
+      var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
+      return values.Any() ? values.GroupBy(x => x).OrderByDescending(g => g.Count()).Select(g => g.Key).First() : emptyValue;
+    }
+
+    public T GetStandardDeviation<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      if (typeof(T) == typeof(double)) {
+        var values = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
+        return values.Any() ? Convert<T>(values.StandardDeviation()) : emptyValue;
+      }
+      // For DateTime, std.dev / variance would have to be TimeSpan
+      //if (typeof(T) == typeof(DateTime)) {
+      //  var values = GetValuesWithoutMissingValues<DateTime>(columnIndex, considerSelection);
+      //  return values.Any() ? Convert<T>(AggregateAsDouble(values, EnumerableStatisticExtensions.StandardDeviation)) : emptyValue;
+      //}
+      return default(T);
+    }
+
+    public T GetVariance<T>(int columnIndex, bool considerSelection = false, T emptyValue = default(T)) {
+      if (typeof(T) == typeof(double)) {
+        var values = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
+        return values.Any() ? Convert<T>(values.Variance()) : emptyValue;
+      }
+      // DateTime variance often overflows long, thus the corresponding DateTime is invalid
+      //if (typeof(T) == typeof(DateTime)) {
+      //  var values = GetValuesWithoutMissingValues<DateTime>(columnIndex, considerSelection);
+      //  return values.Any() ? Convert<T>(AggregateAsDouble(values, EnumerableStatisticExtensions.Variance)) : emptyValue;
+      //}
+      return default(T);
+    }
+
+    public T GetQuantile<T>(double alpha, int columnIndex, bool considerSelection = false, T emptyValue = default(T)) where T : IComparable<T> {
+      if (typeof(T) == typeof(double)) {// IEnumerable<double> is faster  
+        var doubleValues = GetValuesWithoutMissingValues<double>(columnIndex, considerSelection);
+        return doubleValues.Any() ? Convert<T>(doubleValues.Quantile(alpha)) : emptyValue;
+      }
+      var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
+      return values.Any() ? values.Quantile(alpha) : emptyValue;
+    }
+
+    public int GetDistinctValues<T>(int columnIndex, bool considerSelection = false) {
+      var values = GetValuesWithoutMissingValues<T>(columnIndex, considerSelection);
+      return values.GroupBy(x => x).Count();
+    }
+
+    private IEnumerable<T> GetValuesWithoutMissingValues<T>(int columnIndex, bool considerSelection) {
+      return GetValues<T>(columnIndex, considerSelection).Where(x => !IsMissingValue(x));
+    }
+
+    private static DateTime AggregateAsDouble(IEnumerable<DateTime> values, Func<IEnumerable<double>, double> func) {
+      return new DateTime((long)(func(values.Select(x => (double)x.Ticks / TimeSpan.TicksPerSecond)) * TimeSpan.TicksPerSecond));
+    }
+    private static T Convert<T>(object obj) { return (T)obj; }
+
+    public int GetMissingValueCount() {
+      int count = 0;
+      for (int i = 0; i < Columns; ++i) {
+        count += GetMissingValueCount(i);
+      }
+      return count;
+    }
+    public int GetMissingValueCount(int columnIndex) {
+      int sum = 0;
+      for (int i = 0; i < Rows; i++) {
+        if (IsCellEmpty(columnIndex, i))
+          sum++;
+      }
+      return sum;
+    }
+    public int GetRowMissingValueCount(int rowIndex) {
+      int sum = 0;
+      for (int i = 0; i < Columns; i++) {
+        if (IsCellEmpty(i, rowIndex))
+          sum++;
+      }
+      return sum;
+    }
+    #endregion
+
+    #region Helpers
+    private static IList<IList> CopyVariableValues(IList<IList> original) {
+      var copy = new List<IList>(original);
+      for (int i = 0; i < original.Count; ++i) {
+        copy[i] = (IList)Activator.CreateInstance(original[i].GetType(), original[i]);
+      }
+      return copy;
+    }
+    #endregion
   }
 
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/HeuristicLab.DataPreprocessing-3.4.csproj
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/HeuristicLab.DataPreprocessing-3.4.csproj	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/HeuristicLab.DataPreprocessing-3.4.csproj	(revision 15431)
@@ -123,8 +123,4 @@
     <Compile Include="Content\ScatterPlotContent.cs" />
     <Compile Include="Content\DataCompletenessChartContent.cs" />
-    <Compile Include="Data\Columns\DateTimePreprocessingDataColumn.cs" />
-    <Compile Include="Data\Columns\DoublePreprocessingDataColumn.cs" />
-    <Compile Include="Data\Columns\PreprocessingDataColumn.cs" />
-    <Compile Include="Data\Columns\StringPreprocessingDataColumn.cs" />
     <Compile Include="Data\FilteredPreprocessingData.cs" />
     <Compile Include="Content\ManipulationContent.cs" />
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/PreprocessingTransformator.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/PreprocessingTransformator.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/PreprocessingTransformator.cs	(revision 15431)
@@ -83,5 +83,5 @@
           int colIndex = preprocessingData.GetColumnIndex(transformation.Column);
           var originalData = preprocessingData.GetValues<double>(colIndex);
-          originalColumns.Add(transformation.Column, originalData.ToList());
+          originalColumns.Add(transformation.Column, originalData);
         }
       }
@@ -107,5 +107,5 @@
     }
 
-    private IEnumerable<double> ApplyDoubleTransformation(Transformation<double> transformation, IEnumerable<double> data, out bool success, out string errorMsg) {
+    private IEnumerable<double> ApplyDoubleTransformation(Transformation<double> transformation, IList<double> data, out bool success, out string errorMsg) {
       success = transformation.Check(data, out errorMsg);
       // don't apply when the check fails
Index: /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/ProblemDataCreator.cs
===================================================================
--- /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/ProblemDataCreator.cs	(revision 15430)
+++ /branches/DataPreprocessing Cleanup/HeuristicLab.DataPreprocessing/3.4/ProblemDataCreator.cs	(revision 15431)
@@ -129,5 +129,5 @@
     }
 
-    private bool IsNotConstantInputVariable(IEnumerable<double> list) {
+    private bool IsNotConstantInputVariable(IList<double> list) {
       return context.Data.TrainingPartition.End - context.Data.TrainingPartition.Start > 1 || list.Range() > 0;
     }
