|
| 1 | +from math import sqrt |
| 2 | + |
| 3 | + |
1 | 4 | class Result:
|
2 |
| - def __init__(self, tp, tn, overpermission, underpermission): |
3 |
| - self.tp = tp |
4 |
| - self.tn = tn |
5 |
| - self._fp = overpermission |
6 |
| - self._fn = underpermission |
| 5 | + def __init__( |
| 6 | + self, tp: int, tn: int, overpermission: int, underpermission: int |
| 7 | + ): |
| 8 | + self.tp: int = tp |
| 9 | + self.tn: int = tn |
| 10 | + self._fp: int = overpermission |
| 11 | + self._fn: int = underpermission |
7 | 12 |
|
8 | 13 | @property
|
9 |
| - def fp(self): |
| 14 | + def fp(self) -> float: |
10 | 15 | return self._fp
|
11 | 16 |
|
12 | 17 | @property
|
13 |
| - def fn(self): |
| 18 | + def fn(self) -> float: |
14 | 19 | return self._fn
|
15 | 20 |
|
16 |
| - def precision(self): |
| 21 | + def precision(self) -> float: |
| 22 | + """How correct was generator out of allowed accesses.""" |
17 | 23 | return self.tp / (self.tp + self._fp)
|
18 | 24 |
|
19 |
| - def sensitivity(self): |
| 25 | + def sensitivity(self) -> float: |
| 26 | + """How correct was generator detecting which accesses should be allowed |
| 27 | + by reference. |
| 28 | +
|
| 29 | + Also may be called hit rate.""" |
20 | 30 | return self.tp / (self.tp + self._fn)
|
21 | 31 |
|
22 |
| - def tpr(self): |
23 |
| - self.sensitivity() |
| 32 | + def tpr(self) -> float: |
| 33 | + return self.sensitivity() |
| 34 | + |
| 35 | + def f_beta_score(self, beta: float) -> float: |
| 36 | + precision = self.precision() |
| 37 | + recall = self.sensitivity() |
| 38 | + return ( |
| 39 | + (1 + beta**2) |
| 40 | + * precision |
| 41 | + * recall |
| 42 | + / ((beta**2 * precision) + recall) |
| 43 | + ) |
| 44 | + |
| 45 | + def f1(self): |
| 46 | + return self.f_beta_score(1) |
| 47 | + |
| 48 | + def f2(self): |
| 49 | + return self.f_beta_score(2) |
| 50 | + |
| 51 | + def fowlkes_mallows_index(self): |
| 52 | + return sqrt(self.precision() * self.sensitivity()) |
| 53 | + |
| 54 | + def fm(self): |
| 55 | + return self.fowlkes_mallows_index() |
| 56 | + |
| 57 | + def jaccard_index(self): |
| 58 | + return self.tp / (self.tp + self._fn + self.fp) |
24 | 59 |
|
25 |
| - def specificity(self): |
| 60 | + def specificity(self) -> float: |
26 | 61 | return self.tn / (self.tn + self._fp)
|
27 | 62 |
|
28 |
| - def tnr(self): |
29 |
| - self.specificity() |
| 63 | + def tnr(self) -> float: |
| 64 | + return self.specificity() |
30 | 65 |
|
31 |
| - def balanced_precision(self): |
| 66 | + def balanced_precision(self) -> float: |
32 | 67 | return (self.tpr() + self.tnr()) / 2
|
33 | 68 |
|
34 |
| - def summary(self): |
| 69 | + def summary(self) -> str: |
35 | 70 | return f'''hits={self.tp} correct denials={self.tn} overpermission={self._fp} underpermission={self.fn}
|
36 |
| -precision={self.precision()} sensitivity={self.sensitivity()} |
37 |
| -balanced precision={self.balanced_precision()}''' |
| 71 | +precision={self.precision():.2} sensitivity={self.sensitivity():.2} |
| 72 | +f1={self.f1():.2} f2={self.f2():.2} fm={self.fm():.2} csi={self.jaccard_index():.2}''' |
38 | 73 |
|
39 |
| - def __repr__(self): |
| 74 | + def __repr__(self) -> str: |
40 | 75 | return f'Result({self.tp}, {self.tn}, {self._fp}, {self._fn})'
|
41 | 76 |
|
42 |
| - def __str__(self): |
| 77 | + def __str__(self) -> str: |
43 | 78 | return f'({self.tp}, {self.tn}, {self._fp}, {self._fn})'
|
0 commit comments