kwcoco.metrics.confusion_vectors module¶
-
class
kwcoco.metrics.confusion_vectors.
ConfusionVectors
(data, classes, probs=None)[source]¶ Bases:
ubelt.util_mixins.NiceRepr
Stores information used to construct a confusion matrix. This includes corresponding vectors of predicted labels, true labels, sample weights, etc…
Variables: - data (DataFrameArray) – should at least have keys true, pred, weight
- classes (Sequence | CategoryTree) – list of category names or category graph
- probs (ndarray, optional) – probabilities for each class
Example
>>> # xdoctest: IGNORE_WANT >>> from kwcoco.metrics import DetectionMetrics >>> dmet = DetectionMetrics.demo( >>> nimgs=10, nboxes=(0, 10), n_fp=(0, 1), nclasses=3) >>> cfsn_vecs = dmet.confusion_vectors() >>> print(cfsn_vecs.data._pandas()) pred true score weight iou txs pxs gid 0 2 2 10.0000 1.0000 1.0000 0 4 0 1 2 2 7.5025 1.0000 1.0000 1 3 0 2 1 1 5.0050 1.0000 1.0000 2 2 0 3 3 -1 2.5075 1.0000 -1.0000 -1 1 0 4 2 -1 0.0100 1.0000 -1.0000 -1 0 0 5 -1 2 0.0000 1.0000 -1.0000 3 -1 0 6 -1 2 0.0000 1.0000 -1.0000 4 -1 0 7 2 2 10.0000 1.0000 1.0000 0 5 1 8 2 2 8.0020 1.0000 1.0000 1 4 1 9 1 1 6.0040 1.0000 1.0000 2 3 1 .. ... ... ... ... ... ... ... ... 62 -1 2 0.0000 1.0000 -1.0000 7 -1 7 63 -1 3 0.0000 1.0000 -1.0000 8 -1 7 64 -1 1 0.0000 1.0000 -1.0000 9 -1 7 65 1 -1 10.0000 1.0000 -1.0000 -1 0 8 66 1 1 0.0100 1.0000 1.0000 0 1 8 67 3 -1 10.0000 1.0000 -1.0000 -1 3 9 68 2 2 6.6700 1.0000 1.0000 0 2 9 69 2 2 3.3400 1.0000 1.0000 1 1 9 70 3 -1 0.0100 1.0000 -1.0000 -1 0 9 71 -1 2 0.0000 1.0000 -1.0000 2 -1 9
>>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> from kwcoco.metrics.confusion_vectors import ConfusionVectors >>> cfsn_vecs = ConfusionVectors.demo( >>> nimgs=128, nboxes=(0, 10), n_fp=(0, 3), n_fn=(0, 3), nclasses=3) >>> cx_to_binvecs = cfsn_vecs.binarize_ovr() >>> measures = cx_to_binvecs.measures()['perclass'] >>> print('measures = {!r}'.format(measures)) measures = <PerClass_Measures({ 'cat_1': <Measures({'ap': 0.7501, 'auc': 0.7170, 'catname': cat_1, 'max_f1': f1=0.77@0.41, 'max_mcc': mcc=0.71@0.44, 'nsupport': 787.0000, 'realneg_total': 594.0000, 'realpos_total': 193.0000})>, 'cat_2': <Measures({'ap': 0.8288, 'auc': 0.8137, 'catname': cat_2, 'max_f1': f1=0.83@0.40, 'max_mcc': mcc=0.78@0.40, 'nsupport': 787.0000, 'realneg_total': 589.0000, 'realpos_total': 198.0000})>, 'cat_3': <Measures({'ap': 0.7536, 'auc': 0.7150, 'catname': cat_3, 'max_f1': f1=0.77@0.40, 'max_mcc': mcc=0.71@0.42, 'nsupport': 787.0000, 'realneg_total': 578.0000, 'realpos_total': 209.0000})>, }) at 0x7f1b9b0d6130>
>>> kwplot.figure(fnum=1, doclf=True) >>> measures.draw(key='pr', fnum=1, pnum=(1, 3, 1)) >>> measures.draw(key='roc', fnum=1, pnum=(1, 3, 2)) >>> measures.draw(key='mcc', fnum=1, pnum=(1, 3, 3)) ...
-
classmethod
demo
(**kw)[source]¶ Example
>>> cfsn_vecs = ConfusionVectors.demo() >>> print('cfsn_vecs = {!r}'.format(cfsn_vecs)) >>> cx_to_binvecs = cfsn_vecs.binarize_ovr() >>> print('cx_to_binvecs = {!r}'.format(cx_to_binvecs))
-
classmethod
from_arrays
(true, pred=None, score=None, weight=None, probs=None, classes=None)[source]¶ Construct confusion vector data structure from component arrays
Example
>>> import kwarray >>> classes = ['person', 'vehicle', 'object'] >>> rng = kwarray.ensure_rng(0) >>> true = (rng.rand(10) * len(classes)).astype(np.int) >>> probs = rng.rand(len(true), len(classes)) >>> cfsn_vecs = ConfusionVectors.from_arrays(true=true, probs=probs, classes=classes) >>> cfsn_vecs.confusion_matrix() pred person vehicle object real person 0 0 0 vehicle 2 4 1 object 2 1 0
-
confusion_matrix
(raw=False, compress=False)[source]¶ Builds a confusion matrix from the confusion vectors.
Parameters: raw (bool) – if True uses ‘pred_raw’ otherwise used ‘pred’ Returns: - cm : the labeled confusion matrix
- (Note: we should write a efficient replacement for
- this use case. #remove_pandas)
Return type: pd.DataFrame - CommandLine:
- xdoctest -m ~/code/kwcoco/kwcoco/metrics/confusion_vectors.py ConfusionVectors.confusion_matrix
Example
>>> from kwcoco.metrics import DetectionMetrics >>> dmet = DetectionMetrics.demo( >>> nimgs=10, nboxes=(0, 10), n_fp=(0, 1), n_fn=(0, 1), nclasses=3, cls_noise=.2) >>> cfsn_vecs = dmet.confusion_vectors() >>> cm = cfsn_vecs.confusion_matrix() ... >>> print(cm.to_string(float_format=lambda x: '%.2f' % x)) pred background cat_1 cat_2 cat_3 real background 0.00 1.00 1.00 1.00 cat_1 2.00 12.00 0.00 1.00 cat_2 2.00 0.00 14.00 1.00 cat_3 1.00 0.00 1.00 17.00
-
binarize_peritem
(negative_classes=None)[source]¶ Creates a binary representation useful for measuring the performance of detectors. It is assumed that scores of “positive” classes should be high and “negative” clases should be low.
Parameters: negative_classes (List[str | int]) – list of negative class names or idxs, by default chooses any class with a true class index of -1. These classes should ideally have low scores. Returns: BinaryConfusionVectors Example
>>> from kwcoco.metrics import DetectionMetrics >>> dmet = DetectionMetrics.demo( >>> nimgs=10, nboxes=(0, 10), n_fp=(0, 1), nclasses=3) >>> cfsn_vecs = dmet.confusion_vectors() >>> class_idxs = list(dmet.classes.node_to_idx.values()) >>> binvecs = cfsn_vecs.binarize_peritem()
-
binarize_ovr
(mode=1, keyby='name', ignore_classes={'ignore'})[source]¶ Transforms cfsn_vecs into one-vs-rest BinaryConfusionVectors for each category.
Parameters: - mode (int, default=1) – 0 for heirarchy aware or 1 for voc like. MODE 0 IS PROBABLY BROKEN
- keyby (int | str) – can be cx or name
- ignore_classes (Set[str]) – category names to ignore
Returns: - which behaves like
Dict[int, BinaryConfusionVectors]: cx_to_binvecs
Return type: Example
>>> cfsn_vecs = ConfusionVectors.demo() >>> print('cfsn_vecs = {!r}'.format(cfsn_vecs)) >>> catname_to_binvecs = cfsn_vecs.binarize_ovr(keyby='name') >>> print('catname_to_binvecs = {!r}'.format(catname_to_binvecs))
Notes
Consider we want to measure how well we can classify beagles.
Given a multiclass confusion vector, we need to carefully select a subset. We ignore any truth that is coarser than our current label. We also ignore any background predictions on irrelevant classes
dog | dog <- ignore coarser truths dog | cat <- ignore coarser truths dog | beagle <- ignore coarser truths cat | dog cat | cat cat | background <- ignore failures to predict unrelated classes cat | maine-coon beagle | beagle beagle | dog beagle | background beagle | cat Snoopy | beagle Snoopy | cat maine-coon | background <- ignore failures to predict unrelated classes maine-coon | beagle maine-coon | cat
Anything not marked as ignore is counted. We count anything marked as beagle or a finer grained class (e.g. Snoopy) as a positive case. All other cases are negative. The scores come from the predicted probability of beagle, which must be remembered outside the dataframe.
-
class
kwcoco.metrics.confusion_vectors.
OneVsRestConfusionVectors
(cx_to_binvecs, classes)[source]¶ Bases:
ubelt.util_mixins.NiceRepr
Container for multiple one-vs-rest binary confusion vectors
Variables: - cx_to_binvecs –
- classes –
Example
>>> from kwcoco.metrics import DetectionMetrics >>> dmet = DetectionMetrics.demo( >>> nimgs=10, nboxes=(0, 10), n_fp=(0, 1), nclasses=3) >>> cfsn_vecs = dmet.confusion_vectors() >>> self = cfsn_vecs.binarize_ovr(keyby='name') >>> print('self = {!r}'.format(self))
-
class
kwcoco.metrics.confusion_vectors.
BinaryConfusionVectors
(data, cx=None, classes=None)[source]¶ Bases:
ubelt.util_mixins.NiceRepr
Stores information about a binary classification problem. This is always with respect to a specific class, which is given by cx and classes.
- The data DataFrameArray must contain
- is_true - if the row is an instance of class classes[cx] pred_score - the predicted probability of class classes[cx], and weight - sample weight of the example
Example
>>> self = BinaryConfusionVectors.demo(n=10) >>> print('self = {!r}'.format(self)) >>> print('pr = {}'.format(ub.repr2(self.measures()))) >>> print('roc = {}'.format(ub.repr2(self.roc())))
>>> self = BinaryConfusionVectors.demo(n=0) >>> print('pr = {}'.format(ub.repr2(self.measures()))) >>> print('roc = {}'.format(ub.repr2(self.roc())))
>>> self = BinaryConfusionVectors.demo(n=1) >>> print('pr = {}'.format(ub.repr2(self.measures()))) >>> print('roc = {}'.format(ub.repr2(self.roc())))
>>> self = BinaryConfusionVectors.demo(n=2) >>> print('self = {!r}'.format(self)) >>> print('pr = {}'.format(ub.repr2(self.measures()))) >>> print('roc = {}'.format(ub.repr2(self.roc())))
-
classmethod
demo
(n=10, p_true=0.5, p_error=0.2, rng=None)[source]¶ Create random data for tests
Example
>>> from kwcoco.metrics.confusion_vectors import * # NOQA >>> cfsn = BinaryConfusionVectors.demo(n=1000, p_error=0.1) >>> measures = cfsn.measures() >>> print('measures = {}'.format(ub.repr2(measures, nl=1))) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> kwplot.figure(fnum=1, pnum=(1, 2, 1)) >>> measures.draw('pr') >>> kwplot.figure(fnum=1, pnum=(1, 2, 2)) >>> measures.draw('roc')
-
catname
¶
-
precision_recall
(stabalize_thresh=7, stabalize_pad=7, method='sklearn')[source]¶ Deprecated, all information lives in measures now
-
roc
(fp_cutoff=None, stabalize_thresh=7, stabalize_pad=7)[source]¶ Deprecated, all information lives in measures now
-
measures
¶ memoization decorator for a method that respects args and kwargs
References
http://code.activestate.com/recipes/577452-a-memoize-decorator-for-instance-methods/
Example
>>> import ubelt as ub >>> closure = {'a': 'b', 'c': 'd'} >>> incr = [0] >>> class Foo(object): >>> @memoize_method >>> def foo_memo(self, key): >>> value = closure[key] >>> incr[0] += 1 >>> return value >>> def foo(self, key): >>> value = closure[key] >>> incr[0] += 1 >>> return value >>> self = Foo() >>> assert self.foo('a') == 'b' and self.foo('c') == 'd' >>> assert incr[0] == 2 >>> print('Call memoized version') >>> assert self.foo_memo('a') == 'b' and self.foo_memo('c') == 'd' >>> assert incr[0] == 4 >>> assert self.foo_memo('a') == 'b' and self.foo_memo('c') == 'd' >>> print('Counter should no longer increase') >>> assert incr[0] == 4 >>> print('Closure changes result without memoization') >>> closure = {'a': 0, 'c': 1} >>> assert self.foo('a') == 0 and self.foo('c') == 1 >>> assert incr[0] == 6 >>> assert self.foo_memo('a') == 'b' and self.foo_memo('c') == 'd' >>> print('Constructing a new object should get a new cache') >>> self2 = Foo() >>> self2.foo_memo('a') >>> assert incr[0] == 7 >>> self2.foo_memo('a') >>> assert incr[0] == 7
-
class
kwcoco.metrics.confusion_vectors.
Measures
(roc_info)[source]¶ Bases:
ubelt.util_mixins.NiceRepr
,kwcoco.metrics.util.DictProxy
Example
>>> from kwcoco.metrics.confusion_vectors import * # NOQA >>> binvecs = BinaryConfusionVectors.demo(n=100, p_error=0.5) >>> self = binvecs.measures() >>> print('self = {!r}'.format(self)) >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> self.draw(doclf=True) >>> self.draw(key='pr', pnum=(1, 2, 1)) >>> self.draw(key='roc', pnum=(1, 2, 2)) >>> kwplot.show_if_requested()
-
catname
¶
-
draw
(key=None, prefix='', **kw)[source]¶ Example
>>> cfsn_vecs = ConfusionVectors.demo() >>> ovr_cfsn = cfsn_vecs.binarize_ovr(keyby='name') >>> self = ovr_cfsn.measures()['perclass'] >>> self.draw('mcc', doclf=True, fnum=1) >>> self.draw('pr', doclf=1, fnum=2) >>> self.draw('roc', doclf=1, fnum=3)
-
summary_plot
(fnum=1, title='')[source]¶ Example
>>> from kwcoco.metrics.confusion_vectors import * # NOQA >>> cfsn_vecs = ConfusionVectors.demo(n=100, p_error=0.5) >>> binvecs = cfsn_vecs.binarize_peritem() >>> self = binvecs.measures() >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> self.summary_plot() >>> kwplot.show_if_requested()
-
-
class
kwcoco.metrics.confusion_vectors.
PerClass_Measures
(cx_to_info)[source]¶ Bases:
ubelt.util_mixins.NiceRepr
,kwcoco.metrics.util.DictProxy
-
draw
(key='mcc', prefix='', **kw)[source]¶ Example
>>> cfsn_vecs = ConfusionVectors.demo() >>> ovr_cfsn = cfsn_vecs.binarize_ovr(keyby='name') >>> self = ovr_cfsn.measures()['perclass'] >>> self.draw('mcc', doclf=True, fnum=1) >>> self.draw('pr', doclf=1, fnum=2) >>> self.draw('roc', doclf=1, fnum=3)
-
summary_plot
(fnum=1, title='')[source]¶ - CommandLine:
- python ~/code/kwcoco/kwcoco/metrics/confusion_vectors.py PerClass_Measures.summary_plot –show
Example
>>> from kwcoco.metrics.confusion_vectors import * # NOQA >>> from kwcoco.metrics.detect_metrics import DetectionMetrics >>> dmet = DetectionMetrics.demo( >>> n_fp=(0, 5), n_fn=(0, 5), nimgs=128, nboxes=(0, 10), >>> nclasses=3) >>> cfsn_vecs = dmet.confusion_vectors() >>> ovr_cfsn = cfsn_vecs.binarize_ovr(keyby='name') >>> self = ovr_cfsn.measures()['perclass'] >>> # xdoctest: +REQUIRES(--show) >>> import kwplot >>> kwplot.autompl() >>> self.summary_plot(title='demo summary_plot ovr') >>> kwplot.show_if_requested()
-