From 220cca2397f416aafdf5752a3eb2b1a9cd64e37e Mon Sep 17 00:00:00 2001 From: Tobias Schmidt <tobias.schmidt@unibas.ch> Date: Thu, 1 Dec 2011 16:06:28 +0100 Subject: [PATCH] fix bug in roc code: roc code returns None if no true positives are found (otherwise this leads to a division by zero) --- modules/base/pymod/table.py | 20 ++++++++++++++++---- modules/base/tests/test_table.py | 23 +++++++++++++++++++++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/modules/base/pymod/table.py b/modules/base/pymod/table.py index 87a425ebc..fa76ceaed 100644 --- a/modules/base/pymod/table.py +++ b/modules/base/pymod/table.py @@ -1252,6 +1252,11 @@ class Table: fp += 1 x.append(fp) y.append(tp) + + # if no false positives or false negatives values are found return None + if x[-1]==0 or y[-1]==0: + return None + x = [float(v)/x[-1] for v in x] y = [float(v)/y[-1] for v in y] return x,y @@ -1265,10 +1270,12 @@ class Table: try: import numpy as np - rocx, rocy = self.ComputeROC(score_col, class_col, score_dir, - class_dir, class_cutoff) + roc = self.ComputeROC(score_col, class_col, score_dir, + class_dir, class_cutoff) - return np.trapz(rocy, rocx) + if not roc: + return None + return np.trapz(roc[1], roc[0]) except ImportError: LogError("Function needs numpy, but I could not import it.") raise @@ -1284,9 +1291,14 @@ class Table: try: import matplotlib.pyplot as plt - enrx, enry = self.ComputeROC(score_col, class_col, score_dir, + roc = self.ComputeROC(score_col, class_col, score_dir, class_dir, class_cutoff) + if not roc: + return None + + enrx, enry = roc + if not title: title = 'ROC of %s'%score_col diff --git a/modules/base/tests/test_table.py b/modules/base/tests/test_table.py index 4220de12f..e2a3060c6 100644 --- a/modules/base/tests/test_table.py +++ b/modules/base/tests/test_table.py @@ -985,7 +985,15 @@ class TestTable(unittest.TestCase): img1 = Image.open(os.path.join("testfiles","roc-out.png")) img2 = Image.open(os.path.join("testfiles","roc.png")) self.CompareImages(img1, img2) - #pl.show() + + # no true positives + tab = Table(['classific', 'score'], 'bf', + classific=[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False], + score=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1]) + pl = tab.PlotROC(score_col='score', score_dir='+', + class_col='classific', + save=os.path.join("testfiles","roc-out.png")) + self.assertEquals(pl, None) def testPlotROCSameValues(self): if not HAS_MPL or not HAS_PIL: @@ -1011,7 +1019,14 @@ class TestTable(unittest.TestCase): auc = tab.ComputeROCAUC(score_col='score', score_dir='+', class_col='classific') self.assertAlmostEquals(auc, auc_ref) - def testCalcROC(self): + # no true positives + tab = Table(['classific', 'score'], 'bf', + classific=[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False], + score=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1]) + auc = tab.ComputeROCAUC(score_col='score', score_dir='+', class_col='classific') + self.assertEquals(auc, None) + + def testCalcROCAUCWithCutoff(self): if not HAS_NUMPY: return tab = Table(['classific', 'score'], 'ff', @@ -1020,6 +1035,10 @@ class TestTable(unittest.TestCase): auc = tab.ComputeROCAUC(score_col='score', class_col='classific', class_cutoff=0.5) self.assertEquals(auc, 1.0) + # no true positives + auc = tab.ComputeROCAUC(score_col='score', class_col='classific', class_cutoff=1.0) + self.assertEquals(auc, None) + def testCalcROCFromFile(self): tab = Table.Load(os.path.join('testfiles','roc_table.dat')) auc = tab.ComputeROCAUC(score_col='prediction', class_col='reference', class_cutoff=0.4) -- GitLab