POPE Precision, Recall, and F1
Problem Statement
Accuracy alone hides hallucination because POPE splits are balanced by construction. Report precision, recall, and F1 treating "yes" as the positive class — precision is the metric that exposes hallucination.
Background
With "yes" positive, define over the batch:
- TP: answer yes, truth yes.
- FP: answer yes, truth no (a hallucination).
- FN: answer no, truth yes.
Then precision = TP/(TP+FP), recall = TP/(TP+FN), F1 = 2PR/(P+R). When a denominator is 0, that metric is 0.0. Low precision means the model says "yes" to things that are not there.
Your Task
Implement:
def pope_prf(answers, truths):
Return a dict with "precision", "recall", "f1", each rounded to 4 decimals. Comparison is case-insensitive.
Input Format
- answers, truths: equal-length lists of yes/no strings.
Output Format
- A dict of three floats.
Sample
print(pope_prf(["yes", "yes", "no"], ["yes", "no", "yes"]))
Output:
{'precision': 0.5, 'recall': 0.5, 'f1': 0.5}
Example
print(pope_prf(["yes", "yes", "no"], ["yes", "no", "yes"]))
{'precision': 0.5, 'recall': 0.5, 'f1': 0.5}- Compare each answer to its truth value (case-insensitive) to categorize the three samples:
- Sample 1: Answer "yes", Truth "yes" True Positive (TP)
- Sample 2: Answer "yes", Truth "no" False Positive (FP)
- Sample 3: Answer "no", Truth "yes" False Negative (FN)
- Tally the counts from the comparisons: , , .
- Calculate precision, which measures the accuracy of positive predictions: .
- Calculate recall, which measures the ability to find all actual positives: .
- Compute the F1 score, the harmonic mean of precision and recall: .
- The final output is
{'precision': 0.5, 'recall': 0.5, 'f1': 0.5}
Constraints
len(answers) == len(truths),1 <= N <= 100000.- Positive class is
"yes"; compare case-insensitively. - Any metric with a zero denominator is
0.0; round to 4 decimals.