diff --git a/modules/base/pymod/table.py b/modules/base/pymod/table.py index 77951c6344d35e5f66f307a7cb53c868b666b3ad..dae603fb6c606e738ec1987b50aa6c3cac148add 100644 --- a/modules/base/pymod/table.py +++ b/modules/base/pymod/table.py @@ -1511,6 +1511,45 @@ class Table(object): self.AddCol(mean_col_name, 'f', mean_rows) + def Percentiles(self, col, nths): + """ + returns the percentiles of column *col* given in *nths*. + + The percentils are calculated as + + .. code-block:: python + + values[min(len(values), int(round(len(values)*p/100+0.5)-1))] + + where values are the sorted values of *col* not equal to none + :param: nths: list of percentiles to be calculated. Each percentil is a number + between 0 and 100. + + :raises: :class:`TypeError` if column type is ``string`` + :returns: List of percentils in the same order as given in *nths* + """ + idx = self.GetColIndex(col) + col_type = self.col_types[idx] + if col_type!='int' and col_type!='float' and col_type!='bool': + raise TypeError("Median can only be used on numeric column types") + + for nth in nths: + if nth < 0 or nth > 100: + raise ValueError("percentiles must be between 0 and 100") + vals=[] + for v in self[col]: + if v!=None: + vals.append(v) + vals=sorted(vals) + if len(vals)==0: + return [None]*len(nths) + percentiles=[] + + for nth in nths: + p=vals[min(len(vals)-1, int(round(len(vals)*nth/100.0+0.5)-1))] + percentiles.append(p) + return percentiles + def Median(self, col): """ Returns the median of the given column. Cells with None are ignored. Returns diff --git a/modules/base/tests/test_table.py b/modules/base/tests/test_table.py index 13afa0437ea969728fe73a71ba3d20c11cf128d6..b4242473e344f132eaa74f0164f7b16902a11335 100644 --- a/modules/base/tests/test_table.py +++ b/modules/base/tests/test_table.py @@ -196,7 +196,14 @@ class TestTable(unittest.TestCase): self.assertEquals(type(z[0][1]),int) self.assertEquals(type(z[1][1]),int) self.assertRaises(ValueError, tab.Zip, 'col5', 'col3') - + def testPercentiles(self): + tab = Table(['nums'], 'i') + self.assertEqual(tab.Percentiles('nums', [0,100]), [None, None]) + self.assertRaises(ValueError, tab.Percentiles, 'nums', [101]) + self.assertRaises(ValueError, tab.Percentiles, 'nums', [-1]) + for i in (35,15,50,40,20): + tab.AddRow([i]) + self.assertEqual(tab.Percentiles('nums', [0,30,40,100]), [15,20,35,50]) def testTableInitEmpty(self): ''' empty table