diff --git a/doctr/utils/metrics.py b/doctr/utils/metrics.py index 909074a858..d1bbe4abd5 100644 --- a/doctr/utils/metrics.py +++ b/doctr/utils/metrics.py @@ -380,11 +380,10 @@ def summary(self) -> dict[str, float | None]: """ recall = self.matches / self.num_gts if self.num_gts > 0 else None precision = self.matches / self.num_preds if self.num_preds > 0 else None - f1 = ( - 2 * precision * recall / (precision + recall) - if precision is not None and recall is not None and (precision + recall) > 0 - else None - ) + f1 = None + if precision is not None and recall is not None: + # No match at all gives a precision and a recall of 0, so an F1 of 0 + f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0.0 structure_acc = self.struct_matches / self.matches if self.matches > 0 else None return {"recall": recall, "precision": precision, "f1": f1, "structure_acc": structure_acc} diff --git a/tests/common/test_utils_metrics.py b/tests/common/test_utils_metrics.py index 27908233e0..226be73607 100644 --- a/tests/common/test_utils_metrics.py +++ b/tests/common/test_utils_metrics.py @@ -612,5 +612,12 @@ def test_table_cell_metric(use_polygons): res = metric.summary() assert res["recall"] == 0.0 and res["precision"] is None and res["structure_acc"] is None + # Cells on both sides but no match -> recall, precision and F1 are 0 + metric = metrics.TableCellMetric(iou_thresh=0.5, use_polygons=use_polygons) + metric.update(gt_cells[:1], gt_logic[:1], gt_cells[2:], gt_logic[2:]) + res = metric.summary() + assert res["recall"] == 0.0 and res["precision"] == 0.0 and res["f1"] == 0.0 + assert res["structure_acc"] is None + metric.reset() assert metric.num_gts == metric.num_preds == metric.matches == metric.struct_matches == 0