Index: trunk/sources/HeuristicLab.DataAnalysis/Dataset.cs
===================================================================
--- trunk/sources/HeuristicLab.DataAnalysis/Dataset.cs	(revision 232)
+++ trunk/sources/HeuristicLab.DataAnalysis/Dataset.cs	(revision 237)
@@ -39,6 +39,8 @@
     private double[] samples;
     private int rows;
-    Dictionary<int, Dictionary<int, double>>[] cachedMeans;
-    Dictionary<int, Dictionary<int, double>>[] cachedRanges;
+    private Dictionary<int, Dictionary<int, double>>[] cachedMeans;
+    private Dictionary<int, Dictionary<int, double>>[] cachedRanges;
+    private double[] scalingFactor;
+    private double[] scalingOffset;
 
     public int Rows {
@@ -67,5 +69,11 @@
     public double[] Samples {
       get { return samples; }
-      set { 
+      set {
+        scalingFactor = new double[columns];
+        scalingOffset = new double[columns];
+        for(int i = 0; i < scalingFactor.Length; i++) {
+          scalingFactor[i] = 1.0;
+          scalingOffset[i] = 0.0;
+        }
         samples = value;
         CreateDictionaries();
@@ -82,16 +90,16 @@
     public Dataset() {
       Name = "-";
-      VariableNames = new string[] {"Var0"};
+      VariableNames = new string[] { "Var0" };
       Columns = 1;
       Rows = 1;
       Samples = new double[1];
+      scalingOffset = new double[] { 0.0 };
+      scalingFactor = new double[] { 1.0 };
     }
 
     private void CreateDictionaries() {
       // keep a means and ranges dictionary for each column (possible target variable) of the dataset.
-
       cachedMeans = new Dictionary<int, Dictionary<int, double>>[columns];
       cachedRanges = new Dictionary<int, Dictionary<int, double>>[columns];
-
       for(int i = 0; i < columns; i++) {
         cachedMeans[i] = new Dictionary<int, Dictionary<int, double>>();
@@ -115,4 +123,6 @@
       clone.VariableNames = new string[VariableNames.Length];
       Array.Copy(VariableNames, clone.VariableNames, VariableNames.Length);
+      Array.Copy(scalingFactor, clone.scalingFactor, columns);
+      Array.Copy(scalingOffset, clone.scalingOffset, columns);
       return clone;
     }
@@ -129,9 +139,13 @@
       dim2.Value = columns.ToString(CultureInfo.InvariantCulture.NumberFormat);
       node.Attributes.Append(dim2);
-
       XmlAttribute variableNames = document.CreateAttribute("VariableNames");
       variableNames.Value = GetVariableNamesString();
       node.Attributes.Append(variableNames);
-
+      XmlAttribute scalingFactorsAttribute = document.CreateAttribute("ScalingFactors");
+      scalingFactorsAttribute.Value = GetString(scalingFactor);
+      node.Attributes.Append(scalingFactorsAttribute);
+      XmlAttribute scalingOffsetsAttribute = document.CreateAttribute("ScalingOffsets");
+      scalingOffsetsAttribute.Value = GetString(scalingOffset);
+      node.Attributes.Append(scalingOffsetsAttribute);
       node.InnerText = ToString(CultureInfo.InvariantCulture.NumberFormat);
       return node;
@@ -143,6 +157,18 @@
       rows = int.Parse(node.Attributes["Dimension1"].Value, CultureInfo.InvariantCulture.NumberFormat);
       columns = int.Parse(node.Attributes["Dimension2"].Value, CultureInfo.InvariantCulture.NumberFormat);
-      
+
       VariableNames = ParseVariableNamesString(node.Attributes["VariableNames"].Value);
+      if(node.Attributes["ScalingFactors"] != null)
+        scalingFactor = ParseDoubleString(node.Attributes["ScalingFactors"].Value);
+      else {
+        scalingFactor = new double[columns]; // compatibility with old serialization format
+        for(int i = 0; i < scalingFactor.Length; i++) scalingFactor[i] = 1.0;
+      }
+      if(node.Attributes["ScalingOffsets"] != null)
+        scalingOffset = ParseDoubleString(node.Attributes["ScalingOffsets"].Value);
+      else {
+        scalingOffset = new double[columns]; // compatibility with old serialization format
+        for(int i = 0; i < scalingOffset.Length; i++) scalingOffset[i] = 0.0;
+      }
 
       string[] tokens = node.InnerText.Split(';');
@@ -151,5 +177,5 @@
       for(int row = 0; row < rows; row++) {
         for(int column = 0; column < columns; column++) {
-          if(double.TryParse(tokens[row * columns + column], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out samples[row*columns + column]) == false) {
+          if(double.TryParse(tokens[row * columns + column], NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out samples[row * columns + column]) == false) {
             throw new FormatException("Can't parse " + tokens[row * columns + column] + " as double value.");
           }
@@ -168,5 +194,5 @@
         for(int column = 0; column < columns; column++) {
           builder.Append(";");
-          builder.Append(samples[row*columns+column].ToString(format));
+          builder.Append(samples[row * columns + column].ToString(format));
         }
       }
@@ -177,9 +203,20 @@
     private string GetVariableNamesString() {
       string s = "";
-      for (int i = 0; i < variableNames.Length; i++) {
+      for(int i = 0; i < variableNames.Length; i++) {
         s += variableNames[i] + "; ";
       }
 
-      if (variableNames.Length > 0) {
+      if(variableNames.Length > 0) {
+        s = s.TrimEnd(';', ' ');
+      }
+      return s;
+    }
+    private string GetString(double[] xs) {
+      string s = "";
+      for(int i = 0; i < xs.Length; i++) {
+        s += xs[i].ToString(CultureInfo.InvariantCulture) + "; ";
+      }
+
+      if(xs.Length > 0) {
         s = s.TrimEnd(';', ' ');
       }
@@ -189,10 +226,19 @@
     private string[] ParseVariableNamesString(string p) {
       p = p.Trim();
-      string[] tokens = p.Split(new char[] {';'}, StringSplitOptions.RemoveEmptyEntries);
+      string[] tokens = p.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
       return tokens;
     }
+    private double[] ParseDoubleString(string s) {
+      s = s.Trim();
+      string[] ss = s.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
+      double[] xs = new double[ss.Length];
+      for(int i = 0; i < xs.Length; i++) {
+        xs[i] = double.Parse(ss[i], CultureInfo.InvariantCulture);
+      }
+      return xs;
+    }
 
     public double GetMean(int column) {
-      return GetMean(column, 0, Rows-1);
+      return GetMean(column, 0, Rows - 1);
     }
 
@@ -213,5 +259,5 @@
 
     public double GetRange(int column) {
-      return GetRange(column, 0, Rows-1);
+      return GetRange(column, 0, Rows - 1);
     }
 
@@ -248,4 +294,31 @@
       return min;
     }
+
+    internal void ScaleVariable(int column) {
+      if(scalingFactor[column] == 1.0) {
+        double min = GetMinimum(column);
+        double max = GetMaximum(column);
+        double range = max - min;
+        scalingFactor[column] = range;
+        scalingOffset[column] = min;
+        for(int i = 0; i < Rows; i++) {
+          double origValue = samples[i * columns + column];
+          samples[i * columns + column] = (origValue - min) / range;
+        }
+      }
+      CreateDictionaries();
+      FireChanged();
+    }
+
+    internal void UnscaleVariable(int column) {
+      if(scalingFactor[column] != 1.0) {
+        for(int i = 0; i < rows; i++) {
+          double scaledValue = samples[i * columns + column];
+          samples[i * columns + column] = scaledValue * scalingFactor[column] + scalingOffset[column];
+        }
+        scalingFactor[column] = 1.0;
+        scalingOffset[column] = 0.0;
+      }
+    }
   }
 }
