Skip to content

Commit d4673cc

Browse files
Merge pull request #41 from cthoyt/annotate-duplicates
Annotate redundant functions
2 parents 6ec4993 + d71fa25 commit d4673cc

4 files changed

Lines changed: 120 additions & 146 deletions

File tree

rexmex/metrics/classification.py

Lines changed: 95 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -96,61 +96,48 @@ def false_negative(y_true: np.array, y_score: np.array) -> float:
9696
higher_is_better=True,
9797
description="TN / (TN + FP)",
9898
link="https://en.wikipedia.org/wiki/Specificity_(tests)",
99-
binarize=True,
10099
)
101-
def specificity(y_true: np.array, y_score: np.array) -> float:
100+
def true_negative_rate(y_true: np.array, y_score: np.array) -> float:
102101
"""
103-
Calculate the specificity (same as selectivity and true negative rate).
102+
Calculate the true negative rate (duplicated in :func:`specificity` and :func:`selectivity`).
104103
105104
Args:
106105
y_true (array-like): An N x 1 array of ground truth values.
107106
y_score (array-like): An N x 1 array of predicted values.
108107
Returns:
109-
tnr (float): The specificity score.
108+
tnr (float): The true negative rate.
110109
"""
111-
n = condition_negative(y_true)
112-
tn = true_negative(y_true, y_score)
113-
tnr = tn / n
110+
tnr = specificity(y_true, y_score)
114111
return tnr
115112

116113

117-
@classifications.annotate(
118-
lower=0.0,
119-
upper=1.0,
120-
higher_is_better=True,
121-
description="TN / (TN + FP)",
122-
link="https://en.wikipedia.org/wiki/Specificity_(tests)",
123-
)
124-
def selectivity(y_true: np.array, y_score: np.array) -> float:
114+
@classifications.duplicate(true_negative_rate)
115+
def specificity(y_true: np.array, y_score: np.array) -> float:
125116
"""
126-
Calculate the selectivity (same as specificity and true negative rate).
117+
Calculate the specificity (duplicate of :func:`true_negative_rate`).
127118
128119
Args:
129120
y_true (array-like): An N x 1 array of ground truth values.
130121
y_score (array-like): An N x 1 array of predicted values.
131122
Returns:
132-
tnr (float): The selectivity score.
123+
tnr (float): The specificity score.
133124
"""
134-
tnr = specificity(y_true, y_score)
125+
n = condition_negative(y_true)
126+
tn = true_negative(y_true, y_score)
127+
tnr = tn / n
135128
return tnr
136129

137130

138-
@classifications.annotate(
139-
lower=0.0,
140-
upper=1.0,
141-
higher_is_better=True,
142-
description="TN / (TN + FP)",
143-
link="https://en.wikipedia.org/wiki/Specificity_(tests)",
144-
)
145-
def true_negative_rate(y_true: np.array, y_score: np.array) -> float:
131+
@classifications.duplicate(true_negative_rate)
132+
def selectivity(y_true: np.array, y_score: np.array) -> float:
146133
"""
147-
Calculate the true negative rate (same as specificity and selectivity).
134+
Calculate the selectivity (duplicate of :func:`true_negative_rate`).
148135
149136
Args:
150137
y_true (array-like): An N x 1 array of ground truth values.
151138
y_score (array-like): An N x 1 array of predicted values.
152139
Returns:
153-
tnr (float): The true negative rate.
140+
tnr (float): The selectivity score.
154141
"""
155142
tnr = specificity(y_true, y_score)
156143
return tnr
@@ -163,32 +150,24 @@ def true_negative_rate(y_true: np.array, y_score: np.array) -> float:
163150
description="TP / (TP + FN)",
164151
link="https://en.wikipedia.org/wiki/Sensitivity_(test)",
165152
)
166-
def sensitivity(y_true: np.array, y_score: np.array) -> float:
153+
def true_positive_rate(y_true: np.array, y_score: np.array) -> float:
167154
"""
168-
Calculate the sensitivity (same as recall, hit rate and true positive rate).
155+
Calculate the true positive rate (duplicated in :func:`hit_rate`, :func:`sensitivity`, and :func:`recall_score`).
169156
170157
Args:
171158
y_true (array-like): An N x 1 array of ground truth values.
172159
y_score (array-like): An N x 1 array of predicted values.
173160
Returns:
174-
tpr (float): The sensitivity score.
161+
tpr (float): The true positive rate.
175162
"""
176-
p = condition_positive(y_true)
177-
tp = true_positive(y_true, y_score)
178-
tpr = tp / p
163+
tpr = sensitivity(y_true, y_score)
179164
return tpr
180165

181166

182-
@classifications.annotate(
183-
lower=0.0,
184-
upper=1.0,
185-
higher_is_better=True,
186-
description="TP / (TP + FN)",
187-
link="https://en.wikipedia.org/wiki/Sensitivity_(test)",
188-
)
167+
@classifications.duplicate(true_positive_rate)
189168
def hit_rate(y_true: np.array, y_score: np.array) -> float:
190169
"""
191-
Calculate the hit rate (same as recall, sensitivity and true positive rate).
170+
Calculate the hit rate (duplicate of :func:`true_positive_rate`).
192171
193172
Args:
194173
y_true (array-like): An N x 1 array of ground truth values.
@@ -200,27 +179,46 @@ def hit_rate(y_true: np.array, y_score: np.array) -> float:
200179
return tpr
201180

202181

203-
@classifications.annotate(
204-
lower=0.0,
205-
upper=1.0,
206-
higher_is_better=True,
207-
description="TP / (TP + FN)",
208-
link="https://en.wikipedia.org/wiki/Sensitivity_(test)",
209-
)
210-
def true_positive_rate(y_true: np.array, y_score: np.array) -> float:
182+
@classifications.duplicate(true_positive_rate)
183+
def sensitivity(y_true: np.array, y_score: np.array) -> float:
211184
"""
212-
Calculate the true positive rate (same as recall, sensitivity and hit rate).
185+
Calculate the sensitivity (duplicate of :func:`true_positive_rate`).
213186
214187
Args:
215188
y_true (array-like): An N x 1 array of ground truth values.
216189
y_score (array-like): An N x 1 array of predicted values.
217190
Returns:
218-
tpr (float): The true positive rate.
191+
tpr (float): The sensitivity score.
219192
"""
220-
tpr = sensitivity(y_true, y_score)
193+
p = condition_positive(y_true)
194+
tp = true_positive(y_true, y_score)
195+
tpr = tp / p
221196
return tpr
222197

223198

199+
@classifications.duplicate(true_positive_rate, name="Recall", binarize=True)
200+
def recall_score(y_true: np.array, y_score: np.array) -> float:
201+
"""
202+
Calculate the recall for a ground-truth prediction vector pair.
203+
204+
Duplicate of :func:`true_positive_rate`, but with alternate
205+
implementation from :mod:`sklearn`.
206+
207+
Args:
208+
y_true (array-like): An N x 1 array of ground truth values.
209+
y_score (array-like): An N x 1 array of predicted values.
210+
Returns:
211+
recall (float): The value of recall.
212+
213+
.. note::
214+
215+
It's surprising that the sklearn implementation of TPR needs
216+
to be binarized but the rexmex implementation does not
217+
"""
218+
recall = sklearn.metrics.recall_score(y_true, y_score)
219+
return recall
220+
221+
224222
@classifications.annotate(
225223
lower=0.0,
226224
upper=1.0,
@@ -231,7 +229,7 @@ def true_positive_rate(y_true: np.array, y_score: np.array) -> float:
231229
)
232230
def positive_predictive_value(y_true: np.array, y_score: np.array) -> float:
233231
"""
234-
Calculate the positive predictive value (same as precision).
232+
Calculate the positive predictive value (duplicated in :func:`precision_score`).
235233
236234
Args:
237235
y_true (array-like): An N x 1 array of ground truth values.
@@ -248,6 +246,24 @@ def positive_predictive_value(y_true: np.array, y_score: np.array) -> float:
248246
return ppv
249247

250248

249+
@classifications.duplicate(positive_predictive_value, name="Precision")
250+
def precision_score(y_true: np.array, y_score: np.array) -> float:
251+
"""
252+
Calculate the precision for a ground-truth prediction vector pair.
253+
254+
Duplicate of :func:`positive_predictive_value`, but with an
255+
alternate implementation using :mod:`sklearn`.
256+
257+
Args:
258+
y_true (array-like): An N x 1 array of ground truth values.
259+
y_score (array-like): An N x 1 array of predicted values.
260+
Returns:
261+
precision (float): The value of precision.
262+
"""
263+
precision = sklearn.metrics.precision_score(y_true, y_score)
264+
return precision
265+
266+
251267
@classifications.annotate(
252268
lower=0.0,
253269
upper=1.0,
@@ -257,7 +273,7 @@ def positive_predictive_value(y_true: np.array, y_score: np.array) -> float:
257273
)
258274
def negative_predictive_value(y_true: np.array, y_score: np.array) -> float:
259275
"""
260-
Calculate the negative predictive value (same as precision).
276+
Calculate the negative predictive value (duplicted in :func:`precision_score`).
261277
262278
Args:
263279
y_true (array-like): An N x 1 array of ground truth values.
@@ -278,40 +294,34 @@ def negative_predictive_value(y_true: np.array, y_score: np.array) -> float:
278294
description="FN / (FN + TP)",
279295
link="https://en.wikipedia.org/wiki/Type_I_and_type_II_errors#False_positive_and_false_negative_rates",
280296
)
281-
def miss_rate(y_true: np.array, y_score: np.array) -> float:
297+
def false_negative_rate(y_true: np.array, y_score: np.array) -> float:
282298
"""
283-
Calculate the miss rate (same as false negative rate).
299+
Calculate the false negative rate (duplicated in :func:`miss_rate`).
284300
285301
Args:
286302
y_true (array-like): An N x 1 array of ground truth values.
287303
y_score (array-like): An N x 1 array of predicted values.
288304
Returns:
289-
fnr (float): The miss rate value.
305+
fnr (float): The false negative rate value.
290306
"""
291-
fn = false_negative(y_true, y_score)
292-
p = condition_positive(y_true)
293-
fnr = fn / p
307+
fnr = miss_rate(y_true, y_score)
294308
return fnr
295309

296310

297-
@classifications.annotate(
298-
lower=0.0,
299-
upper=1.0,
300-
higher_is_better=False,
301-
description="FN / (FN + TP)",
302-
link="https://en.wikipedia.org/wiki/Type_I_and_type_II_errors#False_positive_and_false_negative_rates",
303-
)
304-
def false_negative_rate(y_true: np.array, y_score: np.array) -> float:
311+
@classifications.duplicate(false_negative_rate)
312+
def miss_rate(y_true: np.array, y_score: np.array) -> float:
305313
"""
306-
Calculate the false negative rate (same as miss rate).
314+
Calculate the miss rate (duplicate of :func:`false_negative_rate`).
307315
308316
Args:
309317
y_true (array-like): An N x 1 array of ground truth values.
310318
y_score (array-like): An N x 1 array of predicted values.
311319
Returns:
312-
fnr (float): The false negative rate value.
320+
fnr (float): The miss rate value.
313321
"""
314-
fnr = miss_rate(y_true, y_score)
322+
fn = false_negative(y_true, y_score)
323+
p = condition_positive(y_true)
324+
fnr = fn / p
315325
return fnr
316326

317327

@@ -322,40 +332,34 @@ def false_negative_rate(y_true: np.array, y_score: np.array) -> float:
322332
description="FP / (FP + TN)",
323333
link="https://en.wikipedia.org/wiki/False_positive_rate",
324334
)
325-
def fall_out(y_true: np.array, y_score: np.array) -> float:
335+
def false_positive_rate(y_true: np.array, y_score: np.array) -> float:
326336
"""
327-
Calculate the fall out (same as false positive rate).
337+
Calculate the false positive rate (duplicated in :func:`false_positive_rate`).
328338
329339
Args:
330340
y_true (array-like): An N x 1 array of ground truth values.
331341
y_score (array-like): An N x 1 array of predicted values.
332342
Returns:
333-
fpr (float): The fall out value.
343+
fpr (float): The false positive rate value.
334344
"""
335-
fp = false_positive(y_true, y_score)
336-
n = condition_negative(y_true)
337-
fpr = fp / n
345+
fpr = fall_out(y_true, y_score)
338346
return fpr
339347

340348

341-
@classifications.annotate(
342-
lower=0.0,
343-
upper=1.0,
344-
higher_is_better=False,
345-
description="FP / (FP + TN)",
346-
link="https://en.wikipedia.org/wiki/False_positive_rate",
347-
)
348-
def false_positive_rate(y_true: np.array, y_score: np.array) -> float:
349+
@classifications.duplicate(false_positive_rate)
350+
def fall_out(y_true: np.array, y_score: np.array) -> float:
349351
"""
350-
Calculate the false positive rate (same as fall out).
352+
Calculate the fall out (duplicate of :func:`false_positive_rate`).
351353
352354
Args:
353355
y_true (array-like): An N x 1 array of ground truth values.
354356
y_score (array-like): An N x 1 array of predicted values.
355357
Returns:
356-
fpr (float): The false positive rate value.
358+
fpr (float): The fall out value.
357359
"""
358-
fpr = fall_out(y_true, y_score)
360+
fp = false_positive(y_true, y_score)
361+
n = condition_negative(y_true)
362+
fpr = fp / n
359363
return fpr
360364

361365

@@ -505,16 +509,10 @@ def threat_score(y_true: np.array, y_score: np.array) -> float:
505509
return ts
506510

507511

508-
@classifications.annotate(
509-
lower=0.0,
510-
upper=1.0,
511-
higher_is_better=True,
512-
description="TP / (TP + FN + FP)",
513-
link="https://rexmex.readthedocs.io/en/latest/modules/root.html#rexmex.metrics.classification.threat_score",
514-
)
512+
@classifications.duplicate(threat_score)
515513
def critical_success_index(y_true: np.array, y_score: np.array) -> float:
516514
"""
517-
Calculate the critical success index (same as the theat score).
515+
Calculate the critical success index (duplicate of :func:`threat_score`).
518516
519517
Args:
520518
y_true (array-like): An N x 1 array of ground truth values.
@@ -714,52 +712,6 @@ def f1_score(y_true: np.array, y_score: np.array) -> float:
714712
return f1
715713

716714

717-
@classifications.annotate(
718-
name="Precision",
719-
lower=0.0,
720-
upper=1.0,
721-
higher_is_better=True,
722-
description="TP / (TP + FP)",
723-
link="https://en.wikipedia.org/wiki/Positive_predictive_value",
724-
binarize=True,
725-
)
726-
def precision_score(y_true: np.array, y_score: np.array) -> float:
727-
"""
728-
Calculate the precision for a ground-truth prediction vector pair.
729-
730-
Args:
731-
y_true (array-like): An N x 1 array of ground truth values.
732-
y_score (array-like): An N x 1 array of predicted values.
733-
Returns:
734-
precision (float): The value of precision.
735-
"""
736-
precision = sklearn.metrics.precision_score(y_true, y_score)
737-
return precision
738-
739-
740-
@classifications.annotate(
741-
name="Recall",
742-
lower=0.0,
743-
upper=1.0,
744-
higher_is_better=True,
745-
description="TP / (TP + FN)",
746-
link="https://en.wikipedia.org/wiki/Sensitivity_(test)",
747-
binarize=True,
748-
)
749-
def recall_score(y_true: np.array, y_score: np.array) -> float:
750-
"""
751-
Calculate the recall for a ground-truth prediction vector pair.
752-
753-
Args:
754-
y_true (array-like): An N x 1 array of ground truth values.
755-
y_score (array-like): An N x 1 array of predicted values.
756-
Returns:
757-
recall (float): The value of recall.
758-
"""
759-
recall = sklearn.metrics.recall_score(y_true, y_score)
760-
return recall
761-
762-
763715
@classifications.annotate(
764716
name="Average precision",
765717
lower=0.0,

0 commit comments

Comments
 (0)