3. ROUGE指标在摘要评估中的应用
任务说明
本案例实现一个轻量级ROUGE指标计算工具,用于评估自动文本摘要与参考摘要之间的重叠质量。你将获得一个可直接运行的Python脚本,输入候选摘要与参考摘要,输出ROUGE-1、ROUGE-2、ROUGE-L的精确率、召回率与F1值,并附带一个最小示例验证计算流程。
核心实现
# rouge_evaluator.py
import re
from collections import Counter
def tokenize(text):
"""将文本转为小写并按非字母数字字符切分为列表"""
return re.findall(r'\w+', text.lower())
def lcs_length(a, b):
"""计算两个序列的最长公共子序列长度"""
m, n = len(a), len(b)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if a[i - 1] == b[j - 1]:
dp[i][j] = dp[i - 1][j - 1] + 1
else:
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
return dp[m][n]
def rouge_n(candidate, reference, n):
"""计算ROUGE-N的精确率、召回率、F1"""
cand_ngrams = Counter(zip(*[candidate[i:] for i in range(n)]))
ref_ngrams = Counter(zip(*[reference[i:] for i in range(n)]))
overlap = sum((cand_ngrams & ref_ngrams).values())
if not cand_ngrams or not ref_ngrams:
return 0.0, 0.0, 0.0
precision = overlap / sum(cand_ngrams.values())
recall = overlap / sum(ref_ngrams.values())
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0.0
return precision, recall, f1
def rouge_l(candidate, reference):
"""计算ROUGE-L(基于最长公共子序列)的精确率、召回率、F1"""
lcs = lcs_length(candidate, reference)
if not candidate or not reference:
return 0.0, 0.0, 0.0
precision = lcs / len(candidate)
recall = lcs / len(reference)
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0.0
return precision, recall, f1
def evaluate(candidate_text, reference_text):
"""计算候选摘要相对参考摘要的ROUGE-1、ROUGE-2、ROUGE-L指标"""
cand_tokens = tokenize(candidate_text)
ref_tokens = tokenize(reference_text)
results = {}
for n in (1, 2):
p, r, f = rouge_n(cand_tokens, ref_tokens, n)
results[f'ROUGE-{n}'] = {'precision': round(p, 4), 'recall': round(r, 4), 'f1': round(f, 4)}
p, r, f = rouge_l(cand_tokens, ref_tokens)
results['ROUGE-L'] = {'precision': round(p, 4), 'recall': round(r, 4), 'f1': round(f, 4)}
return results
if __name__ == '__main__':
# 示例输入
candidate = "The cat sat on the mat and looked at the dog"
reference = "The cat was sitting on the mat watching a dog"
result = evaluate(candidate, reference)
for metric, scores in result.items():
print(f"{metric}: P={scores['precision']:.4f}, R={scores['recall']:.4f}, F1={scores['f1']:.4f}")
运行与验证
将上述代码保存为rouge_evaluator.py,在Python 3.6+环境中执行:
python rouge_evaluator.py
程序会输出三个指标的精确率(P)、召回率(R)与F1值。验证判定标准:
- ROUGE-1的召回率应高于ROUGE-2,因为一元词组重叠比二元词组更容易发生;
- ROUGE-L的F1值应介于ROUGE-1与ROUGE-2之间(因LCS同时考虑词序与长度);
- 所有指标值均在0到1之间,且精确率与召回率满足F1的调和平均关系。
若需验证其他摘要对,直接修改__main__中的candidate与reference字符串即可。
计算逻辑说明
ROUGE-N统计候选摘要与参考摘要之间N元词组(n-gram)的重叠数量。精确率衡量候选摘要中有多少N元词组出现在参考摘要中,召回率衡量参考摘要中有多少N元词组被候选摘要覆盖,F1为两者的调和平均。ROUGE-L则基于最长公共子序列(LCS),在词级别上计算两个摘要的最长匹配序列,能够反映词序信息。本实现采用标准定义,不包含停用词过滤或词干还原,适用于快速原型验证。
预期输出
对于代码中给定的示例输入,根据ROUGE定义可唯一推导出以下结果(保留4位小数):
ROUGE-1: P=0.6364, R=0.7000, F1=0.6667
ROUGE-2: P=0.4000, R=0.4444, F1=0.4211
ROUGE-L: P=0.5455, R=0.6000, F1=0.5714
该输出与代码逻辑严格一致,可用于核对实现是否正确。