Interpolation formula inspired by section 4 of Davis & Goadrich 2006. https://www.biostat.wisc.edu/~page/rocpr.pdf Note here we derive & use a closed formula not present in the paper as follows: Precision = TP / (TP + FP) = TP / P Modeling all of TP (true positive), FP (fal
(self)
| 1748 | }, y_true, y_pred, self.thresholds, sample_weight=sample_weight) |
| 1749 | |
| 1750 | def interpolate_pr_auc(self): |
| 1751 | """Interpolation formula inspired by section 4 of Davis & Goadrich 2006. |
| 1752 | |
| 1753 | https://www.biostat.wisc.edu/~page/rocpr.pdf |
| 1754 | |
| 1755 | Note here we derive & use a closed formula not present in the paper |
| 1756 | as follows: |
| 1757 | |
| 1758 | Precision = TP / (TP + FP) = TP / P |
| 1759 | |
| 1760 | Modeling all of TP (true positive), FP (false positive) and their sum |
| 1761 | P = TP + FP (predicted positive) as varying linearly within each interval |
| 1762 | [A, B] between successive thresholds, we get |
| 1763 | |
| 1764 | Precision slope = dTP / dP |
| 1765 | = (TP_B - TP_A) / (P_B - P_A) |
| 1766 | = (TP - TP_A) / (P - P_A) |
| 1767 | Precision = (TP_A + slope * (P - P_A)) / P |
| 1768 | |
| 1769 | The area within the interval is (slope / total_pos_weight) times |
| 1770 | |
| 1771 | int_A^B{Precision.dP} = int_A^B{(TP_A + slope * (P - P_A)) * dP / P} |
| 1772 | int_A^B{Precision.dP} = int_A^B{slope * dP + intercept * dP / P} |
| 1773 | |
| 1774 | where intercept = TP_A - slope * P_A = TP_B - slope * P_B, resulting in |
| 1775 | |
| 1776 | int_A^B{Precision.dP} = TP_B - TP_A + intercept * log(P_B / P_A) |
| 1777 | |
| 1778 | Bringing back the factor (slope / total_pos_weight) we'd put aside, we get |
| 1779 | |
| 1780 | slope * [dTP + intercept * log(P_B / P_A)] / total_pos_weight |
| 1781 | |
| 1782 | where dTP == TP_B - TP_A. |
| 1783 | |
| 1784 | Note that when P_A == 0 the above calculation simplifies into |
| 1785 | |
| 1786 | int_A^B{Precision.dTP} = int_A^B{slope * dTP} = slope * (TP_B - TP_A) |
| 1787 | |
| 1788 | which is really equivalent to imputing constant precision throughout the |
| 1789 | first bucket having >0 true positives. |
| 1790 | |
| 1791 | Returns: |
| 1792 | pr_auc: an approximation of the area under the P-R curve. |
| 1793 | """ |
| 1794 | dtp = self.true_positives[:self.num_thresholds - |
| 1795 | 1] - self.true_positives[1:] |
| 1796 | p = self.true_positives + self.false_positives |
| 1797 | dp = p[:self.num_thresholds - 1] - p[1:] |
| 1798 | |
| 1799 | prec_slope = math_ops.div_no_nan( |
| 1800 | dtp, math_ops.maximum(dp, 0), name='prec_slope') |
| 1801 | intercept = self.true_positives[1:] - math_ops.multiply(prec_slope, p[1:]) |
| 1802 | |
| 1803 | safe_p_ratio = array_ops.where( |
| 1804 | math_ops.logical_and(p[:self.num_thresholds - 1] > 0, p[1:] > 0), |
| 1805 | math_ops.div_no_nan( |
| 1806 | p[:self.num_thresholds - 1], |
| 1807 | math_ops.maximum(p[1:], 0), |
no test coverage detected