3. ROUGE指标在摘要评估中的应用

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指标计算流程 候选摘要 candidate_text 参考摘要 reference_text 分词与归一化 tokenize() → 小写+正则切分 ROUGE-1 1-gram重叠统计 rouge_n(n=1) ROUGE-2 2-gram重叠统计 rouge_n(n=2) ROUGE-L LCS序列匹配 lcs_length() 输出:P / R / F1 precision = 重叠数 / 候选n-gram总数 recall = 重叠数 / 参考n-gram总数

预期输出

对于代码中给定的示例输入,根据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

该输出与代码逻辑严格一致,可用于核对实现是否正确。