--- a
+++ b/analysis/ml/metrics.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+
+"""This file is part of the TPOT library.
+
+TPOT was primarily developed at the University of Pennsylvania by:
+    - Randal S. Olson (rso@randalolson.com)
+    - Weixuan Fu (weixuanf@upenn.edu)
+    - Daniel Angell (dpa34@drexel.edu)
+    - and many more generous open source contributors
+
+TPOT is free software: you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation, either version 3 of
+the License, or (at your option) any later version.
+
+TPOT 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 Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with TPOT. If not, see <http://www.gnu.org/licenses/>.
+
+"""
+
+import numpy as np
+from sklearn.metrics import make_scorer, SCORERS
+
+
+def balanced_accuracy(y_true, y_pred):
+    """Default scoring function: balanced accuracy.
+
+    Balanced accuracy computes each class' accuracy on a per-class basis using a
+    one-vs-rest encoding, then computes an unweighted average of the class accuracies.
+
+    Parameters
+    ----------
+    y_true: numpy.ndarray {n_samples}
+        True class labels
+    y_pred: numpy.ndarray {n_samples}
+        Predicted class labels by the estimator
+
+    Returns
+    -------
+    fitness: float
+        Returns a float value indicating the individual's balanced accuracy
+        0.5 is as good as chance, and 1.0 is perfect predictive accuracy
+    """
+    all_classes = list(set(np.append(y_true, y_pred)))
+    all_class_accuracies = []
+    for this_class in all_classes:
+        this_class_sensitivity = 0.
+        this_class_specificity = 0.
+        if sum(y_true == this_class) != 0:             
+            this_class_sensitivity = \
+                float(sum((y_pred == this_class) & (y_true == this_class))) /\
+                float(sum((y_true == this_class)))
+
+        if  sum(y_true != this_class) != 0:
+            this_class_specificity = \
+                float(sum((y_pred != this_class) & (y_true != this_class))) /\
+                float(sum((y_true != this_class)))
+            # print('class',this_class,'sensitivity:',this_class_sensitivity)
+            # print('class',this_class,'specifity:',this_class_specificity)
+        this_class_accuracy = (this_class_sensitivity + this_class_specificity) / 2.
+        # print('class',this_class,'accuracy:',this_class_accuracy)
+        all_class_accuracies.append(this_class_accuracy)
+
+    return np.mean(all_class_accuracies)
+
+
+# SCORERS['balanced_accuracy'] = make_scorer(balanced_accuracy)