Skip to content

Commit

Permalink
Add True Negative Rate (TNR) (#541)
Browse files Browse the repository at this point in the history
  • Loading branch information
fcogidi committed Dec 19, 2023
1 parent 35c8f24 commit 2ef534f
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 0 deletions.
3 changes: 3 additions & 0 deletions cyclops/evaluate/metrics/experimental/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
)
from cyclops.evaluate.metrics.experimental.specificity import (
BinarySpecificity,
BinaryTNR,
MulticlassSpecificity,
MulticlassTNR,
MultilabelSpecificity,
MultilabelTNR,
)
3 changes: 3 additions & 0 deletions cyclops/evaluate/metrics/experimental/functional/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
)
from cyclops.evaluate.metrics.experimental.functional.specificity import (
binary_specificity,
binary_tnr,
multiclass_specificity,
multiclass_tnr,
multilabel_specificity,
multilabel_tnr,
)
Original file line number Diff line number Diff line change
Expand Up @@ -441,3 +441,9 @@ def multilabel_specificity(
tn=tn,
fn=fn,
)


# Aliases
binary_tnr = binary_specificity
multiclass_tnr = multiclass_specificity
multilabel_tnr = multilabel_specificity
141 changes: 141 additions & 0 deletions cyclops/evaluate/metrics/experimental/specificity.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,144 @@ def _compute_metric(self) -> Array:
tn=tn,
fn=fn,
)


# Aliases
class BinaryTNR(BinarySpecificity, registry_key="binary_tnr"):
"""The proportion of actual negatives that are correctly identified.
Parameters
----------
threshold : float, default=0.5
Threshold for converting probabilities into binary values.
ignore_index : int, optional
Values in the target array to ignore when computing the metric.
**kwargs
Additional keyword arguments common to all metrics.
Examples
--------
>>> from cyclops.evaluate.metrics.experimental import BinaryTNR
>>> import numpy.array_api as anp
>>> target = anp.asarray([0, 1, 0, 1])
>>> preds = anp.asarray([0, 1, 1, 1])
>>> metric = BinaryTNR()
>>> metric(target, preds)
Array(0.5, dtype=float32)
>>> metric.reset()
>>> target = [[0, 1, 0, 1], [1, 0, 1, 0]]
>>> preds = [[0, 1, 1, 1], [1, 0, 1, 0]]
>>> for t, p in zip(target, preds):
... metric.update(anp.asarray(t), anp.asarray(p))
>>> metric.compute()
Array(0.75, dtype=float32)
"""

name: str = "True Negative Rate"


class MulticlassTNR(MulticlassSpecificity, registry_key="multiclass_tnr"):
"""The proportion of actual negatives that are correctly identified.
Parameters
----------
num_classes : int
The number of classes in the classification task.
top_k : int, default=1
The number of highest probability or logit score predictions to consider
when computing the true negative rate. By default, only the top prediction is
considered. This parameter is ignored if `preds` contains integer values.
average : {'micro', 'macro', 'weighted', 'none'}, optional, default='micro'
Specifies the type of averaging to apply to the true negative rates. Should
be one of the following:
- `'micro'`: Compute the true negative rate globally by considering all
predictions and all targets.
- `'macro'`: Compute the true negative rate for each class individually and
then take the unweighted mean of the true negative rates.
- `'weighted'`: Compute the true negative rate for each class individually
and then take the mean of the true negative rates weighted by the support
(the number of true positives + the number of false negatives) for
each class.
- `'none'` or `None`: Compute the true negative rate for each class individually
and return the scores as an array.
ignore_index : int or tuple of int, optional, default=None
Specifies a target class that is ignored when computing the true negative rate.
Ignoring a target class means that the corresponding predictions do not
contribute to the true negative rate.
Examples
--------
>>> from cyclops.evaluate.metrics.experimental import MulticlassTNR
>>> import numpy.array_api as anp
>>> target = anp.asarray([0, 1, 2, 2, 2])
>>> preds = anp.asarray([0, 0, 2, 2, 1])
>>> metric = MulticlassTNR(num_classes=3)
>>> metric(target, preds)
Array(0.8, dtype=float32)
>>> metric.reset()
>>> target = [[0, 1, 2], [2, 1, 0]]
>>> preds = [[[0.05, 0.95, 0], [0.1, 0.8, 0.1], [0.2, 0.6, 0.2]],
... [[0.1, 0.8, 0.1], [0.05, 0.95, 0], [0.2, 0.6, 0.2]]]
>>> for t, p in zip(target, preds):
... metric.update(anp.asarray(t), anp.asarray(p))
>>> metric.compute()
Array(0.6666667, dtype=float32)
"""

name: str = "True Negative Rate"


class MultilabelTNR(MultilabelSpecificity, registry_key="multilabel_tnr"):
"""The proportion of actual negatives that are correctly identified.
Parameters
----------
num_labels : int
The number of labels in the classification task.
threshold : float, optional, default=0.5
The threshold used to convert probabilities to binary values.
top_k : int, optional, default=1
The number of highest probability predictions to assign the value `1`
(all other predictions are assigned the value `0`). By default, only the
highest probability prediction is considered. This parameter is ignored
if `preds` does not contain floating point values.
average : {'micro', 'macro', 'weighted', 'none'}, optional, default='macro'
Specifies the type of averaging to apply to the true negative rates. Should
be one of the following:
- `'micro'`: Compute the true negative rate globally by considering all
predictions and all targets.
- `'macro'`: Compute the true negative rate for each label individually and
then take the unweighted mean of the true negative rates.
- `'weighted'`: Compute the true negative rate for each label individually
and then take the mean of the true negative rates weighted by the support
(the number of true positives + the number of false negatives) for each
label.
- `'none'` or `None`: Compute the true negative rate for each label individually
and return the scores as an array.
ignore_index : int, optional, default=None
Specifies a value in the target array(s) that is ignored when computing
the true negative rate.
Examples
--------
>>> from cyclops.evaluate.metrics.experimental import MultilabelTNR
>>> import numpy.array_api as anp
>>> target = anp.asarray([[0, 1, 1], [1, 0, 0]])
>>> preds = anp.asarray([[0, 1, 0], [1, 0, 1]])
>>> metric = MultilabelTNR(num_labels=3)
>>> metric(target, preds)
Array(0.6666667, dtype=float32)
>>> metric.reset()
>>> target = [[[0, 1, 1], [1, 0, 0]], [[1, 0, 0], [0, 1, 1]]]
>>> preds = [[[0.05, 0.95, 0], [0.1, 0.8, 0.1]],
... [[0.1, 0.8, 0.1], [0.05, 0.95, 0]]]
>>> for t, p in zip(target, preds):
... metric.update(anp.asarray(t), anp.asarray(p))
>>> metric.compute()
Array(0.6666667, dtype=float32)
"""

name: str = "True Negative Rate"

0 comments on commit 2ef534f

Please sign in to comment.