|
|
|
@ -6,25 +6,35 @@ class Weights(NamedTuple):
|
|
|
|
|
"""Represent weights/costs for editing operations."""
|
|
|
|
|
|
|
|
|
|
deletes: int = 1
|
|
|
|
|
"""Cost for a delete ad -> a."""
|
|
|
|
|
inserts: int = 1
|
|
|
|
|
"""Cost for an insert a -> ai."""
|
|
|
|
|
replacements: int = 1
|
|
|
|
|
"""Cost for a replacement ab -> ar."""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MetricResult(NamedTuple):
|
|
|
|
|
"""Represent a result from a metric calculation."""
|
|
|
|
|
|
|
|
|
|
metric: str
|
|
|
|
|
"""Name of the metric that calculated this results."""
|
|
|
|
|
weights: Weights
|
|
|
|
|
"""The `Weights`/costs used to calculate this result."""
|
|
|
|
|
weighted_errors: int
|
|
|
|
|
"""The weighted errors calculated by the metric."""
|
|
|
|
|
reference_elements: int
|
|
|
|
|
"""Number of elements in the reference string."""
|
|
|
|
|
compared_elements: int
|
|
|
|
|
"""Number of elements in the string that is evaluated."""
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def accuracy(self) -> float:
|
|
|
|
|
"""The accuracy calculated as 1 - errors / reference_elements."""
|
|
|
|
|
return 1 - self.error_rate
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def error_rate(self) -> float:
|
|
|
|
|
"""The error rate calculated by errors / reference_elements."""
|
|
|
|
|
if self.reference_elements <= 0 and self.compared_elements <= 0:
|
|
|
|
|
return 0
|
|
|
|
|
elif self.reference_elements <= 0:
|
|
|
|
@ -34,7 +44,7 @@ class MetricResult(NamedTuple):
|
|
|
|
|
def get_dict(self) -> Dict:
|
|
|
|
|
"""Combines the properties to a dictionary.
|
|
|
|
|
|
|
|
|
|
We deviate from the builtin _asdict() function by including our properties.
|
|
|
|
|
We deviate from the builtin `_asdict()` function by including our properties.
|
|
|
|
|
"""
|
|
|
|
|
return {
|
|
|
|
|
**{key: value for key, value in self._asdict().items()},
|
|
|
|
@ -50,19 +60,19 @@ def bag_accuracy(
|
|
|
|
|
weights: Weights,
|
|
|
|
|
metric: str = "bag_accuracy",
|
|
|
|
|
) -> MetricResult:
|
|
|
|
|
"""Calculates the the weighted errors for two bags (Counter).
|
|
|
|
|
"""Calculates the the weighted errors for two bags (Multiset, `Counter`).
|
|
|
|
|
|
|
|
|
|
Basic algorithm idea:
|
|
|
|
|
- All elements in reference not occurring in compared are considered deletes.
|
|
|
|
|
- All elements in compared not occurring in reference are considered inserts.
|
|
|
|
|
- All elements in `reference` not occurring in `compared` are considered deletes.
|
|
|
|
|
- All elements in `compared` not occurring in `reference` are considered inserts.
|
|
|
|
|
- When the cost for one replacement is lower than that of one insert and one delete
|
|
|
|
|
we can substitute pairs of deletes and inserts with one replacement.
|
|
|
|
|
|
|
|
|
|
:param reference: Bag used as reference (ground truth).
|
|
|
|
|
:param compared: Bag used to compare (ocr).
|
|
|
|
|
:param weights: Weights/costs for editing operations.
|
|
|
|
|
:param weights: `Weights`/costs for editing operations.
|
|
|
|
|
:param metric: Name of the (original) metric.
|
|
|
|
|
:return: NamedTuple representing the results of this metric.
|
|
|
|
|
:return: `NamedTuple` representing the results of this metric.
|
|
|
|
|
"""
|
|
|
|
|
n_ref = sum(reference.values())
|
|
|
|
|
n_cmp = sum(compared.values())
|
|
|
|
|