Repository: jitsi/jiwer
Issue: Permutations of the sentences give different results
Root cause: Algorithmic Error

Thanks for open-sourcing this library.

By default, the sentences are concatenated together using `jiwer.SentencesToListOfWords()`. Therefore, different permutations of the (ground_truth, hypothesis) pairs give different results.

```python
ground_truth = ["I", "am I good?"]
hypothesis = ["I am", "I good?"]
print(wer(ground_truth, hypothesis))
# prints 0.0


ground_truth = ["am I good?", "I"]
hypothesis = ["I good?", "I am"]
print(wer(ground_truth, hypothesis))
# prints 0.5
```

So it seems that this formulation is not suitable to compute WER on a test set of sentences. Am I missing something?

You're right - permutations of the input list do give different results due to the concatenation of all elements of the list into a single string over which the edit distance is computed.

I initially designed this library for evaluating meeting transcriptions. This has a baked-in assumption that multiple sentences are ordered, and share context.  I ran into the problem that the transcription of the meeting (as a list of sentences) and the hypothesis of a speech-to-text engine (as a list of sentences) did not overlap nicely, e.g the lists had different lengths. However, for this use-case, the implementation as-is is desired, as you would never permute the lists.

I agree that when you're evaluating, say librispeech, you would want invariance when permuting the (gt, hypothesis) tuples.

Do you have any suggestions for improving the current API?




Thanks for you reply. I understand the original purpose of the library, and that this library is not suitable for evaluating WER over a set of utterances like librispeech.
I am therefore surprised that several implementations ([here](https://huggingface.co/facebook/wav2vec2-base-960h#evaluation), [here](https://blog.machinetranslation.io/compute-wer-score), [here](https://huggingface.co/ctl/wav2vec2-large-xlsr-cantonese/blob/main/cer.py#L116), ...) use the [wer function](https://github.com/jitsi/jiwer/blob/8c6671e045205bdfc99790571ef33d6e3832ca71/jiwer/measures.py#L65) of this library for their evaluation.

It might be important to make it clear that the [wer function](https://github.com/jitsi/jiwer/blob/8c6671e045205bdfc99790571ef33d6e3832ca71/jiwer/measures.py#L65) of this library is not suitable for that purpose. 
When evaluating on a set of utterances like librispeech, the edit distance should be computed independently for each utterance. In the case of a test set of short utterances, the performance difference is significant and unfair when comparing against approaches that use the correct implementation.

The following function computes the edit distance independently for each utterance:
```python
def wer(
  truth: List[str],
  hypothesis: List[str],
  truth_transform: Union[tr.Compose, tr.AbstractTransform] = _default_transform,
  hypothesis_transform: Union[tr.Compose, tr.AbstractTransform] = _default_transform,
  **kwargs
) -> float:
  """
  Calculate word error rate (WER) between a set of ground-truth sentences and
  a set of hypothesis sentences.
  :return: WER as a floating point number
  """
  # raise an error if the number of ground-truth sentences and the number of 
  # hypothesis sentences differ.
  if len(truth) != len(hypothesis):
    raise ValueError("the number of ground-truth sentences and the number "
                     "of hypothesis sentences differ")
  hits, substitutions, deletions, insertions = 0, 0, 0, 0
  for (truth_sample, hypothesis_sample) in zip(truth, hypothesis):
    m = compute_measures(
        truth_sample, hypothesis_sample, truth_transform, hypothesis_transform, **kwargs
    )
    hits += m["hits"]
    substitutions += m["substitutions"]
    deletions += m["deletions"]
    insertions += m["insertions"]
            
  error = substitutions + deletions + insertions
  total = substitutions + deletions + hits

  return error / total
```



This issue should be fixed from version 2.3.0 onwards.