Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/HeuristicLab.Algorithms.DataAnalysis.Views-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/HeuristicLab.Algorithms.DataAnalysis.Views-3.4.csproj	(revision 13099)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/HeuristicLab.Algorithms.DataAnalysis.Views-3.4.csproj	(revision 13100)
@@ -166,4 +166,8 @@
     <Compile Include="NcaDimensionReductionView.Designer.cs">
       <DependentUpon>NcaDimensionReductionView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="OneRClassificationModelView.cs" />
+    <Compile Include="OneRClassificationModelView.Designer.cs">
+      <DependentUpon>OneRClassificationModelView.cs</DependentUpon>
     </Compile>
     <Compile Include="Plugin.cs" />
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/OneRClassificationModelView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/OneRClassificationModelView.Designer.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/OneRClassificationModelView.Designer.cs	(revision 13100)
@@ -0,0 +1,135 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Algorithms.DataAnalysis.Views {
+  partial class OneRClassificationModelView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.dataGridView = new System.Windows.Forms.DataGridView();
+      this.intervalstart = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.intervalend = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.classcolumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
+      this.variableLabel = new System.Windows.Forms.Label();
+      this.MissingValuesClassLabel = new System.Windows.Forms.Label();
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // dataGridView
+      // 
+      this.dataGridView.AllowUserToAddRows = false;
+      this.dataGridView.AllowUserToDeleteRows = false;
+      this.dataGridView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+      this.dataGridView.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
+            this.intervalstart,
+            this.intervalend,
+            this.classcolumn});
+      this.dataGridView.Location = new System.Drawing.Point(3, 32);
+      this.dataGridView.Name = "dataGridView";
+      this.dataGridView.ReadOnly = true;
+      this.dataGridView.Size = new System.Drawing.Size(389, 230);
+      this.dataGridView.TabIndex = 0;
+      // 
+      // intervalstart
+      // 
+      this.intervalstart.HeaderText = "Interval start (inclusive)";
+      this.intervalstart.Name = "intervalstart";
+      this.intervalstart.ReadOnly = true;
+      // 
+      // intervalend
+      // 
+      this.intervalend.HeaderText = "Interval end (exclusive)";
+      this.intervalend.Name = "intervalend";
+      this.intervalend.ReadOnly = true;
+      // 
+      // classcolumn
+      // 
+      this.classcolumn.HeaderText = "Class";
+      this.classcolumn.Name = "classcolumn";
+      this.classcolumn.ReadOnly = true;
+      // 
+      // variableLabel
+      // 
+      this.variableLabel.AutoSize = true;
+      this.variableLabel.Location = new System.Drawing.Point(3, 10);
+      this.variableLabel.Name = "variableLabel";
+      this.variableLabel.Size = new System.Drawing.Size(48, 13);
+      this.variableLabel.TabIndex = 1;
+      this.variableLabel.Text = "Variable:";
+      // 
+      // MissingValuesClassLabel
+      // 
+      this.MissingValuesClassLabel.Anchor = System.Windows.Forms.AnchorStyles.Top;
+      this.MissingValuesClassLabel.AutoSize = true;
+      this.MissingValuesClassLabel.Location = new System.Drawing.Point(165, 10);
+      this.MissingValuesClassLabel.Name = "MissingValuesClassLabel";
+      this.MissingValuesClassLabel.Size = new System.Drawing.Size(118, 13);
+      this.MissingValuesClassLabel.TabIndex = 2;
+      this.MissingValuesClassLabel.Text = "Class of missing values:";
+      // 
+      // OneRClassificationModelView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.MissingValuesClassLabel);
+      this.Controls.Add(this.variableLabel);
+      this.Controls.Add(this.dataGridView);
+      this.Name = "OneRClassificationModelView";
+      this.Size = new System.Drawing.Size(395, 265);
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.DataGridView dataGridView;
+    private System.Windows.Forms.Label variableLabel;
+    private System.Windows.Forms.DataGridViewTextBoxColumn intervalstart;
+    private System.Windows.Forms.DataGridViewTextBoxColumn intervalend;
+    private System.Windows.Forms.DataGridViewTextBoxColumn classcolumn;
+    private System.Windows.Forms.Label MissingValuesClassLabel;
+  }
+}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/OneRClassificationModelView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/OneRClassificationModelView.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis.Views/3.4/OneRClassificationModelView.cs	(revision 13100)
@@ -0,0 +1,75 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Windows.Forms;
+using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.Views {
+  [View("OneR Classification Model")]
+  [Content(typeof(OneRClassificationModel), IsDefaultView = true)]
+  public partial class OneRClassificationModelView : AsynchronousContentView {
+    public OneRClassificationModelView() {
+      InitializeComponent();
+    }
+
+    public new OneRClassificationModel Content {
+      get { return (OneRClassificationModel)base.Content; }
+      set { base.Content = value; }
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      UpdateDataGridView();
+    }
+
+    private void UpdateDataGridView() {
+      if (InvokeRequired) {
+        Invoke((Action)UpdateDataGridView);
+      } else {
+        if (Content == null) {
+          variableLabel.Text = "Variable: ";
+          MissingValuesClassLabel.Text = "Class of missing values: ";
+          dataGridView.Rows.Clear();
+        } else {
+          variableLabel.Text = "Variable: " + Content.Variable;
+          MissingValuesClassLabel.Text = "Class of missing values: " + Content.MissingValuesClass;
+
+          dataGridView.RowCount = Content.Classes.Length;
+
+          for (int row = 0; row < Content.Classes.Length; row++) {
+            if (row == 0) {
+              dataGridView[0, row].Value = Double.NegativeInfinity;
+            } else {
+              dataGridView[0, row].Value = Content.Splits[row - 1];
+            }
+            dataGridView[1, row].Value = Content.Splits[row];
+            dataGridView[2, row].Value = Content.Classes[row];
+          }
+
+          dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.ColumnHeader);
+          dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders);
+        }
+      }
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneR.cs	(revision 13100)
@@ -0,0 +1,169 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// 1R classification algorithm.
+  /// </summary>
+  [Item("OneR Classification", "A simple classification algorithm the searches the best single-variable split (does not support categorical features correctly). See R.C. Holte (1993). Very simple classification rules perform well on most commonly used datasets. Machine Learning. 11:63-91.")]
+  [StorableClass]
+  public sealed class OneR : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+
+    public IValueParameter<IntValue> MinBucketSizeParameter {
+      get { return (IValueParameter<IntValue>)Parameters["MinBucketSize"]; }
+    }
+
+    [StorableConstructor]
+    private OneR(bool deserializing) : base(deserializing) { }
+
+    private OneR(OneR original, Cloner cloner)
+      : base(original, cloner) { }
+
+    public OneR()
+      : base() {
+      Parameters.Add(new ValueParameter<IntValue>("MinBucketSize", "Minimum size of a bucket for numerical values. (Except for the rightmost bucket)", new IntValue(6)));
+      Problem = new ClassificationProblem();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OneR(this, cloner);
+    }
+
+    protected override void Run() {
+      var solution = CreateOneRSolution(Problem.ProblemData, MinBucketSizeParameter.Value.Value);
+      Results.Add(new Result("OneR solution", "The 1R classifier.", solution));
+    }
+
+    public static IClassificationSolution CreateOneRSolution(IClassificationProblemData problemData, int minBucketSize = 6) {
+      var bestClassified = 0;
+      List<Split> bestSplits = null;
+      string bestVariable = string.Empty;
+      double bestMissingValuesClass = double.NaN;
+      var classValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices);
+
+      foreach (var variable in problemData.AllowedInputVariables) {
+        var inputValues = problemData.Dataset.GetDoubleValues(variable, problemData.TrainingIndices);
+        var samples = inputValues.Zip(classValues, (i, v) => new Sample(i, v)).OrderBy(s => s.inputValue);
+
+        var missingValuesDistribution = samples.Where(s => double.IsNaN(s.inputValue)).GroupBy(s => s.classValue).ToDictionary(s => s.Key, s => s.Count()).MaxItems(s => s.Value).FirstOrDefault();
+
+        //calculate class distributions for all distinct inputValues
+        List<Dictionary<double, int>> classDistributions = new List<Dictionary<double, int>>();
+        List<double> thresholds = new List<double>();
+        double lastValue = double.NaN;
+        foreach (var sample in samples.Where(s => !double.IsNaN(s.inputValue))) {
+          if (sample.inputValue > lastValue || double.IsNaN(lastValue)) {
+            if (!double.IsNaN(lastValue)) thresholds.Add((lastValue + sample.inputValue) / 2);
+            lastValue = sample.inputValue;
+            classDistributions.Add(new Dictionary<double, int>());
+            foreach (var classValue in problemData.ClassValues)
+              classDistributions[classDistributions.Count - 1][classValue] = 0;
+
+          }
+          classDistributions[classDistributions.Count - 1][sample.classValue]++;
+        }
+        thresholds.Add(double.PositiveInfinity);
+
+        var distribution = classDistributions[0];
+        var threshold = thresholds[0];
+        var splits = new List<Split>();
+
+        for (int i = 1; i < classDistributions.Count; i++) {
+          var samplesInSplit = distribution.Max(d => d.Value);
+          //join splits if there are too few samples in the split or the distributions has the same maximum class value as the current split
+          if (samplesInSplit < minBucketSize ||
+            classDistributions[i].MaxItems(d => d.Value).Select(d => d.Key).Contains(
+              distribution.MaxItems(d => d.Value).Select(d => d.Key).First())) {
+            foreach (var classValue in classDistributions[i])
+              distribution[classValue.Key] += classValue.Value;
+            threshold = thresholds[i];
+          } else {
+            splits.Add(new Split(threshold, distribution.MaxItems(d => d.Value).Select(d => d.Key).First()));
+            distribution = classDistributions[i];
+            threshold = thresholds[i];
+          }
+        }
+        splits.Add(new Split(double.PositiveInfinity, distribution.MaxItems(d => d.Value).Select(d => d.Key).First()));
+
+        int correctClassified = 0;
+        int splitIndex = 0;
+        foreach (var sample in samples.Where(s => !double.IsNaN(s.inputValue))) {
+          while (sample.inputValue >= splits[splitIndex].thresholdValue)
+            splitIndex++;
+          correctClassified += sample.classValue == splits[splitIndex].classValue ? 1 : 0;
+        }
+        correctClassified += missingValuesDistribution.Value;
+
+        if (correctClassified > bestClassified) {
+          bestClassified = correctClassified;
+          bestSplits = splits;
+          bestVariable = variable;
+          bestMissingValuesClass = missingValuesDistribution.Value == 0 ? double.NaN : missingValuesDistribution.Key;
+        }
+      }
+
+      //remove neighboring splits with the same class value
+      for (int i = 0; i < bestSplits.Count - 1; i++) {
+        if (bestSplits[i].classValue == bestSplits[i + 1].classValue) {
+          bestSplits.Remove(bestSplits[i]);
+          i--;
+        }
+      }
+
+      var model = new OneRClassificationModel(bestVariable, bestSplits.Select(s => s.thresholdValue).ToArray(), bestSplits.Select(s => s.classValue).ToArray(), bestMissingValuesClass);
+      var solution = new OneRClassificationSolution(model, (IClassificationProblemData)problemData.Clone());
+
+      return solution;
+    }
+
+    #region helper classes
+    private class Split {
+      public double thresholdValue;
+      public double classValue;
+
+      public Split(double thresholdValue, double classValue) {
+        this.thresholdValue = thresholdValue;
+        this.classValue = classValue;
+      }
+    }
+
+    private class Sample {
+      public double inputValue;
+      public double classValue;
+
+      public Sample(double inputValue, double classValue) {
+        this.inputValue = inputValue;
+        this.classValue = classValue;
+      }
+    }
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationModel.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationModel.cs	(revision 13100)
@@ -0,0 +1,115 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item("OneR Classification Model", "A model that uses intervals for one variable to determine the class.")]
+  public class OneRClassificationModel : NamedItem, IClassificationModel {
+    [Storable]
+    protected string variable;
+    public string Variable {
+      get { return variable; }
+    }
+
+    [Storable]
+    protected double[] splits;
+    public double[] Splits {
+      get { return splits; }
+    }
+
+    [Storable]
+    protected double[] classes;
+    public double[] Classes {
+      get { return classes; }
+    }
+
+    [Storable]
+    protected double missingValuesClass;
+    public double MissingValuesClass {
+      get { return missingValuesClass; }
+    }
+
+    [StorableConstructor]
+    protected OneRClassificationModel(bool deserializing) : base(deserializing) { }
+    protected OneRClassificationModel(OneRClassificationModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.variable = (string)original.variable;
+      this.splits = (double[])original.splits.Clone();
+      this.classes = (double[])original.classes.Clone();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new OneRClassificationModel(this, cloner); }
+
+    public OneRClassificationModel(string variable, double[] splits, double[] classes, double missingValuesClass = double.NaN)
+      : base() {
+      if (splits.Length != classes.Length) {
+        throw new ArgumentException("Number of splits and classes has to be equal.");
+      }
+      if (!Double.IsPositiveInfinity(splits[splits.Length - 1])) {
+        throw new ArgumentException("Last split has to be double.PositiveInfinity, so that all values are covered.");
+      }
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.variable = variable;
+      this.splits = splits;
+      this.classes = classes;
+      this.missingValuesClass = missingValuesClass;
+    }
+
+    // uses sorting to return the values in the order of rows, instead of using nested for loops
+    // to avoid O(n²) runtime
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      var values = dataset.GetDoubleValues(Variable, rows).ToArray();
+      var rowsArray = rows.ToArray();
+      var order = Enumerable.Range(0, rowsArray.Length).ToArray();
+      double[] estimated = new double[rowsArray.Length];
+      Array.Sort(rowsArray, order);
+      Array.Sort(values, rowsArray);
+      int curSplit = 0, curIndex = 0;
+      while (curIndex < values.Length && Double.IsNaN(values[curIndex])) {
+        estimated[curIndex] = MissingValuesClass;
+        curIndex++;
+      }
+      while (curSplit < Splits.Length) {
+        while (curIndex < values.Length && Splits[curSplit] > values[curIndex]) {
+          estimated[curIndex] = classes[curSplit];
+          curIndex++;
+        }
+        curSplit++;
+      }
+      Array.Sort(rowsArray, estimated);
+      Array.Sort(order, estimated);
+      return estimated;
+    }
+
+    public IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new OneRClassificationSolution(this, new ClassificationProblemData(problemData));
+    }
+
+  }
+}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationSolution.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/OneRClassificationSolution.cs	(revision 13100)
@@ -0,0 +1,48 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "OneR Classification Solution", Description = "Represents a OneR classification solution which uses only a single feature with potentially multiple thresholds for class prediction.")]
+  public class OneRClassificationSolution : ClassificationSolution {
+    public new OneRClassificationModel Model {
+      get { return (OneRClassificationModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected OneRClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected OneRClassificationSolution(OneRClassificationSolution original, Cloner cloner) : base(original, cloner) { }
+    public OneRClassificationSolution(OneRClassificationModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OneRClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/BaselineClassifiers/ZeroR.cs	(revision 13100)
@@ -0,0 +1,71 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis {
+  /// <summary>
+  /// 0R classification algorithm.
+  /// </summary>
+  [Item("ZeroR Classification", "The simplest possible classifier, ZeroR always predicts the majority class.")]
+  [StorableClass]
+  public sealed class ZeroR : FixedDataAnalysisAlgorithm<IClassificationProblem> {
+
+    [StorableConstructor]
+    private ZeroR(bool deserializing) : base(deserializing) { }
+    private ZeroR(ZeroR original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public ZeroR()
+      : base() {
+      Problem = new ClassificationProblem();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ZeroR(this, cloner);
+    }
+
+    protected override void Run() {
+      var solution = CreateZeroRSolution(Problem.ProblemData);
+      Results.Add(new Result("ZeroR solution", "The simplest possible classifier, ZeroR always predicts the majority class.", solution));
+    }
+
+    public static IClassificationSolution CreateZeroRSolution(IClassificationProblemData problemData) {
+      var dataset = problemData.Dataset;
+      string target = problemData.TargetVariable;
+      var targetValues = dataset.GetDoubleValues(target, problemData.TrainingIndices);
+
+
+      // if multiple classes have the same number of observations then simply take the first one
+      var dominantClass = targetValues.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count())
+        .MaxItems(kvp => kvp.Value).Select(x => x.Key).First();
+
+      var model = new ConstantModel(dominantClass);
+      var solution = model.CreateClassificationSolution(problemData);
+      return solution;
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithmStatic.cs
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithmStatic.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/GradientBoostedTreesAlgorithmStatic.cs	(revision 13100)
@@ -96,5 +96,5 @@
         weights = new List<double>();
         // add constant model
-        models.Add(new ConstantRegressionModel(f0));
+        models.Add(new ConstantModel(f0));
         weights.Add(1.0);
       }
Index: /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 13099)
+++ /trunk/sources/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 13100)
@@ -122,4 +122,8 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="BaselineClassifiers\OneR.cs" />
+    <Compile Include="BaselineClassifiers\OneRClassificationModel.cs" />
+    <Compile Include="BaselineClassifiers\OneRClassificationSolution.cs" />
+    <Compile Include="BaselineClassifiers\ZeroR.cs" />
     <Compile Include="CrossValidation.cs">
       <SubType>Code</SubType>
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionComparisonView.Designer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionComparisonView.Designer.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionComparisonView.Designer.cs	(revision 13100)
@@ -0,0 +1,80 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Problems.DataAnalysis.Views.Classification {
+  partial class ClassificationSolutionComparisonView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.dataGridView = new System.Windows.Forms.DataGridView();
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit();
+      this.SuspendLayout();
+      // 
+      // dataGridView
+      // 
+      this.dataGridView.AllowUserToAddRows = false;
+      this.dataGridView.AllowUserToDeleteRows = false;
+      this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+      this.dataGridView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.dataGridView.Location = new System.Drawing.Point(0, 0);
+      this.dataGridView.Name = "dataGridView";
+      this.dataGridView.ReadOnly = true;
+      this.dataGridView.Size = new System.Drawing.Size(418, 257);
+      this.dataGridView.TabIndex = 0;
+      this.dataGridView.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.dataGridView_MouseDoubleClick);
+      // 
+      // ClassificationSolutionComparisonView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.dataGridView);
+      this.Name = "ClassificationSolutionComparisonView";
+      this.Size = new System.Drawing.Size(418, 257);
+      ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit();
+      this.ResumeLayout(false);
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.DataGridView dataGridView;
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionComparisonView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionComparisonView.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/ClassificationSolutionComparisonView.cs	(revision 13100)
@@ -0,0 +1,154 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Algorithms.DataAnalysis;
+using HeuristicLab.MainForm;
+using HeuristicLab.Problems.DataAnalysis.OnlineCalculators;
+
+namespace HeuristicLab.Problems.DataAnalysis.Views.Classification {
+  [View("Classification Solution Comparions")]
+  [Content(typeof(IClassificationSolution))]
+  public partial class ClassificationSolutionComparisonView : DataAnalysisSolutionEvaluationView {
+    private List<IClassificationSolution> solutions;
+
+    public ClassificationSolutionComparisonView() {
+      InitializeComponent();
+    }
+
+    public new IClassificationSolution Content {
+      get { return (IClassificationSolution)base.Content; }
+      set { base.Content = value; }
+    }
+
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.ModelChanged += new EventHandler(Content_ModelChanged);
+      Content.ProblemDataChanged += new EventHandler(Content_ProblemDataChanged);
+    }
+    protected override void DeregisterContentEvents() {
+      base.DeregisterContentEvents();
+      Content.ModelChanged -= new EventHandler(Content_ModelChanged);
+      Content.ProblemDataChanged -= new EventHandler(Content_ProblemDataChanged);
+    }
+
+    protected virtual void Content_ModelChanged(object sender, EventArgs e) {
+      if (InvokeRequired) Invoke((Action<object, EventArgs>)Content_ModelChanged, sender, e);
+      else UpdateDataGridView();
+    }
+    protected virtual void Content_ProblemDataChanged(object sender, EventArgs e) {
+      if (InvokeRequired) Invoke((Action<object, EventArgs>)Content_ProblemDataChanged, sender, e);
+      else {
+        UpdateDataGridView();
+      }
+    }
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      UpdateDataGridView();
+    }
+
+    private void UpdateDataGridView() {
+      if (InvokeRequired) {
+        Invoke((Action)UpdateDataGridView);
+      } else {
+        if (Content == null) {
+          dataGridView.Rows.Clear();
+          dataGridView.Columns.Clear();
+          solutions.Clear();
+        } else {
+
+          IClassificationProblemData problemData = Content.ProblemData;
+          var dataset = problemData.Dataset;
+          solutions = new List<IClassificationSolution>() { Content };
+          solutions.AddRange(GenerateClassificationSolutions(problemData));
+
+          dataGridView.ColumnCount = 4;
+          dataGridView.RowCount = solutions.Count();
+          dataGridView.Columns[0].HeaderText = "Accuracy (training)";
+          dataGridView.Columns[1].HeaderText = "Accuracy (test)";
+          dataGridView.Columns[2].HeaderText = "Matthews Correlation Coefficient (training)";
+          dataGridView.Columns[3].HeaderText = "Matthews Correlation Coefficient (test)";
+          if (problemData.Classes == 2) {
+            dataGridView.ColumnCount = 6;
+            dataGridView.Columns[4].HeaderText = "F1 Score (training)";
+            dataGridView.Columns[5].HeaderText = "F1 Score (test)";
+          }
+
+          for (int row = 0; row < solutions.Count; row++) {
+            var solution = solutions[row];
+
+            dataGridView.Rows[row].HeaderCell.Value = solution.Name;
+            dataGridView[0, row].Value = solution.TrainingAccuracy;
+            dataGridView[1, row].Value = solution.TestAccuracy;
+
+            var trainingIndizes = problemData.TrainingIndices;
+            var originalTrainingValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, trainingIndizes);
+            var estimatedTrainingValues = solution.Model.GetEstimatedClassValues(dataset, trainingIndizes);
+
+            var testIndices = problemData.TestIndices;
+            var originalTestValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, testIndices);
+            var estimatedTestValues = solution.Model.GetEstimatedClassValues(dataset, testIndices);
+
+            OnlineCalculatorError errorState;
+            dataGridView[2, row].Value = MatthewsCorrelationCoefficientCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+            dataGridView[3, row].Value = MatthewsCorrelationCoefficientCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+            if (problemData.Classes == 2) {
+              dataGridView[4, row].Value = FOneScoreCalculator.Calculate(originalTrainingValues, estimatedTrainingValues, out errorState);
+              dataGridView[5, row].Value = FOneScoreCalculator.Calculate(originalTestValues, estimatedTestValues, out errorState);
+            }
+          }
+
+          dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.ColumnHeader);
+          dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders);
+        }
+      }
+    }
+
+    private IEnumerable<IClassificationSolution> GenerateClassificationSolutions(IClassificationProblemData problemData) {
+      var newSolutions = new List<IClassificationSolution>();
+      var zeroR = ZeroR.CreateZeroRSolution(problemData);
+      zeroR.Name = "ZeroR Classification Solution";
+      newSolutions.Add(zeroR);
+      var oneR = OneR.CreateOneRSolution(problemData);
+      oneR.Name = "OneR Classification Solution";
+      newSolutions.Add(oneR);
+      try {
+        var lda = LinearDiscriminantAnalysis.CreateLinearDiscriminantAnalysisSolution(problemData);
+        lda.Name = "Linear Discriminant Analysis Solution";
+        newSolutions.Add(lda);
+      }
+      catch (NotSupportedException) { }
+      catch (ArgumentException) { }
+      return newSolutions;
+    }
+
+    private void dataGridView_MouseDoubleClick(object sender, MouseEventArgs e) {
+      var hittestinfo = dataGridView.HitTest(e.X, e.Y);
+      if (hittestinfo.Type != DataGridViewHitTestType.RowHeader) { return; }
+      if (hittestinfo.RowIndex > solutions.Count) { return; }
+
+      MainFormManager.MainForm.ShowContent(solutions[hittestinfo.RowIndex]);
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/DiscriminantFunctionClassificationSolutionThresholdView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/DiscriminantFunctionClassificationSolutionThresholdView.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Classification/DiscriminantFunctionClassificationSolutionThresholdView.cs	(revision 13100)
@@ -46,5 +46,5 @@
 
     private Dictionary<double, Series> classValueSeriesMapping;
-    private Random random;
+    private System.Random random;
     private bool updateInProgress;
 
@@ -54,5 +54,5 @@
 
       classValueSeriesMapping = new Dictionary<double, Series>();
-      random = new Random();
+      random = new System.Random();
       updateInProgress = false;
 
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/HeuristicLab.Problems.DataAnalysis.Views-3.4.csproj	(revision 13100)
@@ -137,4 +137,8 @@
     <Compile Include="Classification\ClassificationFeatureCorrelationView.Designer.cs">
       <DependentUpon>ClassificationFeatureCorrelationView.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Classification\ClassificationSolutionComparisonView.cs" />
+    <Compile Include="Classification\ClassificationSolutionComparisonView.Designer.cs">
+      <DependentUpon>ClassificationSolutionComparisonView.cs</DependentUpon>
     </Compile>
     <Compile Include="Classification\ClassificationTimeframeFeatureCorrelationView.cs">
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionErrorCharacteristicsCurveView.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionErrorCharacteristicsCurveView.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Views/3.4/Regression/RegressionSolutionErrorCharacteristicsCurveView.cs	(revision 13100)
@@ -292,6 +292,6 @@
     private IRegressionSolution CreateConstantSolution() {
       double averageTrainingTarget = ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).Average();
-      var model = new ConstantRegressionModel(averageTrainingTarget);
-      var solution = new ConstantRegressionSolution(model, (IRegressionProblemData)ProblemData.Clone());
+      var model = new ConstantModel(averageTrainingTarget);
+      var solution = model.CreateRegressionSolution(ProblemData);
       solution.Name = "Baseline (constant)";
       return solution;
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/HeuristicLab.Problems.DataAnalysis-3.4.csproj	(revision 13100)
@@ -130,8 +130,10 @@
     <Compile Include="Implementation\Classification\ClassificationEnsembleProblemData.cs" />
     <Compile Include="Implementation\Classification\ClassificationSolutionBase.cs" />
+    <Compile Include="Implementation\Classification\ConstantClassificationSolution.cs" />
     <Compile Include="Implementation\Classification\DiscriminantFunctionClassificationSolutionBase.cs" />
     <Compile Include="Implementation\Clustering\ClusteringProblem.cs" />
     <Compile Include="Implementation\Clustering\ClusteringProblemData.cs" />
     <Compile Include="Implementation\Clustering\ClusteringSolution.cs" />
+    <Compile Include="Implementation\Regression\ConstantModel.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionModel.cs" />
     <Compile Include="Implementation\Regression\ConstantRegressionSolution.cs" />
@@ -182,8 +184,11 @@
     <Compile Include="OnlineCalculators\AutoCorrelationCalculator.cs" />
     <Compile Include="OnlineCalculators\ClassificationPerformanceMeasuresCalculator.cs" />
+    <Compile Include="OnlineCalculators\ConfusionMatrixCalculator.cs" />
     <Compile Include="OnlineCalculators\DependencyCalculator\HoeffdingsDependenceCalculator.cs" />
     <Compile Include="OnlineCalculators\DependencyCalculator\PearsonsRDependenceCalculator.cs" />
     <Compile Include="OnlineCalculators\DependencyCalculator\PearsonsRSquaredDependenceCalculator.cs" />
     <Compile Include="OnlineCalculators\DependencyCalculator\SpearmansRankCorrelationCoefficientCalculator.cs" />
+    <Compile Include="OnlineCalculators\FOneScoreCalculator.cs" />
+    <Compile Include="OnlineCalculators\MatthewsCorrelationCoefficientCalculator.cs" />
     <Compile Include="OnlineCalculators\OnlineBoundedMeanSquaredErrorCalculator.cs" />
     <Compile Include="OnlineCalculators\OnlineCovarianceCalculator.cs" />
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationPerformanceMeasures.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationPerformanceMeasures.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationPerformanceMeasures.cs	(revision 13100)
@@ -37,4 +37,6 @@
     protected const string TrainingFalsePositiveRateResultName = "False positive rate (training)";
     protected const string TrainingFalseDiscoveryRateResultName = "False discovery rate (training)";
+    protected const string TrainingF1ScoreResultName = "F1 score (training)";
+    protected const string TrainingMatthewsCorrelationResultName = "Matthews Correlation (training)";
     protected const string TestTruePositiveRateResultName = "True positive rate (test)";
     protected const string TestTrueNegativeRateResultName = "True negative rate (test)";
@@ -43,4 +45,6 @@
     protected const string TestFalsePositiveRateResultName = "False positive rate (test)";
     protected const string TestFalseDiscoveryRateResultName = "False discovery rate (test)";
+    protected const string TestF1ScoreResultName = "F1 score (test)";
+    protected const string TestMatthewsCorrelationResultName = "Matthews Correlation (test)";
     #endregion
 
@@ -89,4 +93,12 @@
       set { ((DoubleValue)this[TrainingFalseDiscoveryRateResultName].Value).Value = value; }
     }
+    public double TrainingF1Score {
+      get { return ((DoubleValue)this[TrainingF1ScoreResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingF1ScoreResultName].Value).Value = value; }
+    }
+    public double TrainingMatthewsCorrelation {
+      get { return ((DoubleValue)this[TrainingMatthewsCorrelationResultName].Value).Value; }
+      set { ((DoubleValue)this[TrainingMatthewsCorrelationResultName].Value).Value = value; }
+    }
     public double TestTruePositiveRate {
       get { return ((DoubleValue)this[TestTruePositiveRateResultName].Value).Value; }
@@ -113,4 +125,12 @@
       set { ((DoubleValue)this[TestFalseDiscoveryRateResultName].Value).Value = value; }
     }
+    public double TestF1Score {
+      get { return ((DoubleValue)this[TestF1ScoreResultName].Value).Value; }
+      set { ((DoubleValue)this[TestF1ScoreResultName].Value).Value = value; }
+    }
+    public double TestMatthewsCorrelation {
+      get { return ((DoubleValue)this[TestMatthewsCorrelationResultName].Value).Value; }
+      set { ((DoubleValue)this[TestMatthewsCorrelationResultName].Value).Value = value; }
+    }
     #endregion
 
@@ -123,4 +143,6 @@
       Add(new Result(TrainingFalsePositiveRateResultName, "The false positive rate is the complement of the true negative rate of the model on the training partition.", new PercentValue()));
       Add(new Result(TrainingFalseDiscoveryRateResultName, "The false discovery rate is the complement of the positive predictive value of the model on the training partition.", new PercentValue()));
+      Add(new Result(TrainingF1ScoreResultName, "The F1 score of the model on the training partition.", new DoubleValue()));
+      Add(new Result(TrainingMatthewsCorrelationResultName, "The Matthews correlation value of the model on the training partition.", new DoubleValue()));
       Add(new Result(TestTruePositiveRateResultName, "Sensitivity/True positive rate of the model on the test partition\n(TP/(TP+FN)).", new PercentValue()));
       Add(new Result(TestTrueNegativeRateResultName, "Specificity/True negative rate of the model on the test partition\n(TN/(FP+TN)).", new PercentValue()));
@@ -129,4 +151,6 @@
       Add(new Result(TestFalsePositiveRateResultName, "The false positive rate is the complement of the true negative rate of the model on the test partition.", new PercentValue()));
       Add(new Result(TestFalseDiscoveryRateResultName, "The false discovery rate is the complement of the positive predictive value of the model on the test partition.", new PercentValue()));
+      Add(new Result(TestF1ScoreResultName, "The F1 score of the model on the test partition.", new DoubleValue()));
+      Add(new Result(TrainingMatthewsCorrelationResultName, "The Matthews correlation value of the model on the test partition.", new DoubleValue()));
       TrainingTruePositiveRate = double.NaN;
       TrainingTrueNegativeRate = double.NaN;
@@ -135,4 +159,6 @@
       TrainingFalsePositiveRate = double.NaN;
       TrainingFalseDiscoveryRate = double.NaN;
+      TrainingF1Score = double.NaN;
+      TrainingMatthewsCorrelation = double.NaN;
       TestTruePositiveRate = double.NaN;
       TestTrueNegativeRate = double.NaN;
@@ -141,4 +167,6 @@
       TestFalsePositiveRate = double.NaN;
       TestFalseDiscoveryRate = double.NaN;
+      TestF1Score = double.NaN;
+      TestMatthewsCorrelation = double.NaN;
     }
 
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ClassificationSolutionBase.cs	(revision 13100)
@@ -26,4 +26,5 @@
 using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis.OnlineCalculators;
 
 namespace HeuristicLab.Problems.DataAnalysis {
@@ -135,4 +136,15 @@
       if (testPerformanceCalculator.ErrorState == OnlineCalculatorError.None)
         ClassificationPerformanceMeasures.SetTestResults(testPerformanceCalculator);
+
+      var f1Training = FOneScoreCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+      if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TrainingF1Score = f1Training;
+      var f1Test = FOneScoreCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+      if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TestF1Score = f1Test;
+
+
+      var mccTraining = MatthewsCorrelationCoefficientCalculator.Calculate(originalTrainingClassValues, estimatedTrainingClassValues, out errorState);
+      if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TrainingMatthewsCorrelation = mccTraining;
+      var mccTest = MatthewsCorrelationCoefficientCalculator.Calculate(originalTestClassValues, estimatedTestClassValues, out errorState);
+      if (errorState == OnlineCalculatorError.None) ClassificationPerformanceMeasures.TestMatthewsCorrelation = mccTest;
     }
 
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ConstantClassificationSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ConstantClassificationSolution.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Classification/ConstantClassificationSolution.cs	(revision 13100)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item(Name = "Constant Classification Solution", Description = "Represents a constant classification solution (model + data).")]
+  public class ConstantClassificationSolution : ClassificationSolution {
+    public new ConstantModel Model {
+      get { return (ConstantModel)base.Model; }
+      set { base.Model = value; }
+    }
+
+    [StorableConstructor]
+    protected ConstantClassificationSolution(bool deserializing) : base(deserializing) { }
+    protected ConstantClassificationSolution(ConstantClassificationSolution original, Cloner cloner) : base(original, cloner) { }
+    public ConstantClassificationSolution(ConstantModel model, IClassificationProblemData problemData)
+      : base(model, problemData) {
+      RecalculateResults();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new ConstantClassificationSolution(this, cloner);
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantModel.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantModel.cs	(revision 13100)
@@ -0,0 +1,99 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis {
+  [StorableClass]
+  [Item("Constant Model", "A model that always returns the same constant value regardless of the presented input data.")]
+  public class ConstantModel : NamedItem, IRegressionModel, IClassificationModel, ITimeSeriesPrognosisModel, IStringConvertibleValue {
+    [Storable]
+    private double constant;
+    public double Constant {
+      get { return constant; }
+      // setter not implemented because manipulation of the constant is not allowed
+    }
+
+    [StorableConstructor]
+    protected ConstantModel(bool deserializing) : base(deserializing) { }
+    protected ConstantModel(ConstantModel original, Cloner cloner)
+      : base(original, cloner) {
+      this.constant = original.constant;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new ConstantModel(this, cloner); }
+
+    public ConstantModel(double constant)
+      : base() {
+      this.name = ItemName;
+      this.description = ItemDescription;
+      this.constant = constant;
+      this.ReadOnly = true; // changing a constant regression model is not supported
+    }
+
+    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
+      return rows.Select(row => Constant);
+    }
+    public IEnumerable<double> GetEstimatedClassValues(IDataset dataset, IEnumerable<int> rows) {
+      return GetEstimatedValues(dataset, rows);
+    }
+    public IEnumerable<IEnumerable<double>> GetPrognosedValues(IDataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons) {
+      return rows.Select(_ => horizons.Select(__ => Constant));
+    }
+
+    public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
+      return new ConstantRegressionSolution(this, new RegressionProblemData(problemData));
+    }
+    public IClassificationSolution CreateClassificationSolution(IClassificationProblemData problemData) {
+      return new ConstantClassificationSolution(this, new ClassificationProblemData(problemData));
+    }
+    public ITimeSeriesPrognosisSolution CreateTimeSeriesPrognosisSolution(ITimeSeriesPrognosisProblemData problemData) {
+      return new TimeSeriesPrognosisSolution(this, new TimeSeriesPrognosisProblemData(problemData));
+    }
+
+    public override string ToString() {
+      return string.Format("Constant: {0}", GetValue());
+    }
+
+    #region IStringConvertibleValue
+    public bool ReadOnly { get; private set; }
+    public bool Validate(string value, out string errorMessage) {
+      throw new NotSupportedException(); // changing a constant regression model is not supported
+    }
+
+    public string GetValue() {
+      return string.Format("{0:E4}", constant);
+    }
+
+    public bool SetValue(string value) {
+      throw new NotSupportedException(); // changing a constant regression model is not supported
+    }
+
+    public event EventHandler ValueChanged;
+    #endregion
+
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionModel.cs	(revision 13100)
@@ -31,4 +31,5 @@
   [StorableClass]
   [Item("Constant Regression Model", "A model that always returns the same constant value regardless of the presented input data.")]
+  [Obsolete]
   public class ConstantRegressionModel : NamedItem, IRegressionModel, IStringConvertibleValue {
     [Storable]
@@ -60,5 +61,5 @@
 
     public IRegressionSolution CreateRegressionSolution(IRegressionProblemData problemData) {
-      return new ConstantRegressionSolution(this, new RegressionProblemData(problemData));
+      return new ConstantRegressionSolution(new ConstantModel(constant), new RegressionProblemData(problemData));
     }
 
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/ConstantRegressionSolution.cs	(revision 13100)
@@ -28,6 +28,6 @@
   [Item(Name = "Constant Regression Solution", Description = "Represents a constant regression solution (model + data).")]
   public class ConstantRegressionSolution : RegressionSolution {
-    public new ConstantRegressionModel Model {
-      get { return (ConstantRegressionModel)base.Model; }
+    public new ConstantModel Model {
+      get { return (ConstantModel)base.Model; }
       set { base.Model = value; }
     }
@@ -36,5 +36,5 @@
     protected ConstantRegressionSolution(bool deserializing) : base(deserializing) { }
     protected ConstantRegressionSolution(ConstantRegressionSolution original, Cloner cloner) : base(original, cloner) { }
-    public ConstantRegressionSolution(ConstantRegressionModel model, IRegressionProblemData problemData)
+    public ConstantRegressionSolution(ConstantModel model, IRegressionProblemData problemData)
       : base(model, problemData) {
       RecalculateResults();
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/Models/ConstantTimeSeriesPrognosisModel.cs	(revision 13100)
@@ -20,4 +20,5 @@
 #endregion
 
+using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -29,4 +30,5 @@
   [StorableClass]
   [Item("Constant TimeSeries Model", "A time series model that returns for all prediciton the same constant value.")]
+  [Obsolete]
   public class ConstantTimeSeriesPrognosisModel : ConstantRegressionModel, ITimeSeriesPrognosisModel {
     [StorableConstructor]
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisResults.cs	(revision 13100)
@@ -373,5 +373,5 @@
       //mean model
       double trainingMean = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).Average();
-      var meanModel = new ConstantTimeSeriesPrognosisModel(trainingMean);
+      var meanModel = new ConstantModel(trainingMean);
 
       //AR1 model
@@ -448,5 +448,5 @@
         //mean model
         double trainingMean = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).Average();
-        var meanModel = new ConstantTimeSeriesPrognosisModel(trainingMean);
+        var meanModel = new ConstantModel(trainingMean);
 
         //AR1 model
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 13099)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/TimeSeriesPrognosis/TimeSeriesPrognosisSolutionBase.cs	(revision 13100)
@@ -150,5 +150,5 @@
       OnlineCalculatorError errorState;
       double trainingMean = ProblemData.TrainingIndices.Any() ? ProblemData.Dataset.GetDoubleValues(ProblemData.TargetVariable, ProblemData.TrainingIndices).Average() : double.NaN;
-      var meanModel = new ConstantTimeSeriesPrognosisModel(trainingMean);
+      var meanModel = new ConstantModel(trainingMean);
 
       double alpha, beta;
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ConfusionMatrixCalculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ConfusionMatrixCalculator.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/ConfusionMatrixCalculator.cs	(revision 13100)
@@ -0,0 +1,72 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis.OnlineCalculators {
+  public class ConfusionMatrixCalculator {
+    public static double[,] Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      if (originalValues.Count() != estimatedValues.Count()) {
+        throw new ArgumentException("Number of elements in originalValues and estimatedValues enumerations doesn't match.");
+      }
+
+      var  classValues = originalValues.Distinct().ToList();
+      var estimatedClassValues = estimatedValues.Distinct().ToList();
+
+      if (!estimatedClassValues.All(x => classValues.Contains(x))) {
+        errorState = OnlineCalculatorError.InvalidValueAdded;
+        return null;
+      }
+
+      int classes = classValues.Count;
+      double[,] confusionMatrix = new double[classes, classes];
+
+      Dictionary<double, int> classValueIndexMapping = new Dictionary<double, int>();
+      int index = 0;
+      foreach (double classValue in classValues.OrderBy(x => x)) {
+        classValueIndexMapping.Add(classValue, index);
+        index++;
+      }
+
+      IEnumerator<double> originalEnumerator = originalValues.GetEnumerator();
+      IEnumerator<double> estimatedEnumerator = estimatedValues.GetEnumerator();
+      int originalIndex;
+      int estimatedIndex;
+      while (originalEnumerator.MoveNext() & estimatedEnumerator.MoveNext()) {
+        if (!classValueIndexMapping.TryGetValue(originalEnumerator.Current, out originalIndex)) {
+          errorState = OnlineCalculatorError.InvalidValueAdded;
+          return null;
+        }
+        if (!classValueIndexMapping.TryGetValue(estimatedEnumerator.Current, out estimatedIndex)) {
+          errorState = OnlineCalculatorError.InvalidValueAdded;
+          return null;
+        }
+
+        confusionMatrix[estimatedIndex, originalIndex] += 1;
+      }
+
+      errorState = OnlineCalculatorError.None;
+      return confusionMatrix;
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/FOneScoreCalculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/FOneScoreCalculator.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/FOneScoreCalculator.cs	(revision 13100)
@@ -0,0 +1,47 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Problems.DataAnalysis.OnlineCalculators {
+  public class FOneScoreCalculator {
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      if (originalValues.Distinct().Skip(2).Any()) {
+        throw new ArgumentException("F1 score can only be calculated for binary classification.");
+      }
+
+      var confusionMatrix = ConfusionMatrixCalculator.Calculate(originalValues, estimatedValues, out errorState);
+      if (!errorState.Equals(OnlineCalculatorError.None)) {
+        return double.NaN;
+      }
+      return CalculateFOne(confusionMatrix);
+    }
+
+    private static double CalculateFOne(double[,] confusionMatrix) {
+      double precision = confusionMatrix[0, 0] / (confusionMatrix[0, 0] + confusionMatrix[0, 1]);
+      double recall = confusionMatrix[0, 0] / (confusionMatrix[0, 0] + confusionMatrix[1, 0]);
+
+      return 2 * ((precision * recall) / (precision + recall));
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/MatthewsCorrelationCoefficientCalculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/MatthewsCorrelationCoefficientCalculator.cs	(revision 13100)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/OnlineCalculators/MatthewsCorrelationCoefficientCalculator.cs	(revision 13100)
@@ -0,0 +1,79 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.Problems.DataAnalysis.OnlineCalculators {
+  public class MatthewsCorrelationCoefficientCalculator {
+    public static double Calculate(IEnumerable<double> originalValues, IEnumerable<double> estimatedValues, out OnlineCalculatorError errorState) {
+      var confusionMatrix = ConfusionMatrixCalculator.Calculate(originalValues, estimatedValues, out errorState);
+      if (!errorState.Equals(OnlineCalculatorError.None)) {
+        return double.NaN;
+      }
+      return CalculateMCC(confusionMatrix);
+    }
+
+    private static double CalculateMCC(double[,] confusionMatrix) {
+      if (confusionMatrix.GetLength(0) != confusionMatrix.GetLength(1)) {
+        throw new ArgumentException("Confusion matrix is not a square matrix.");
+      }
+
+      int classes = confusionMatrix.GetLength(0);
+      double numerator = 0;
+      for (int k = 0; k < classes; k++) {
+        for (int l = 0; l < classes; l++) {
+          for (int m = 0; m < classes; m++) {
+            numerator += confusionMatrix[k, k] * confusionMatrix[m, l] - confusionMatrix[l, k] * confusionMatrix[k, m];
+          }
+        }
+      }
+
+      double denominator1 = 0;
+      double denominator2 = 0;
+      for (int k = 0; k < classes; k++) {
+        double clk = 0;
+        double cgf = 0;
+        double ckl = 0;
+        double cfg = 0;
+        for (int l = 0; l < classes; l++) {
+          clk += confusionMatrix[l, k];
+          ckl += confusionMatrix[k, l];
+        }
+        for (int f = 0; f < classes; f++) {
+          if (f == k) {
+            continue;
+          }
+          for (int g = 0; g < classes; g++) {
+            cgf += confusionMatrix[g, f];
+            cfg += confusionMatrix[f, g];
+          }
+        }
+        denominator1 += clk * cgf;
+        denominator2 += ckl * cfg;
+      }
+      denominator1 = Math.Sqrt(denominator1);
+      denominator2 = Math.Sqrt(denominator2);
+
+      return numerator / (denominator1 * denominator2);
+    }
+  }
+}
