4. METEOR指标实现与语义匹配

任务说明

本案例实现METEOR(Metric for Evaluation of Translation with Explicit ORdering)指标,用于评估机器翻译或文本生成结果与参考文本之间的语义匹配质量。METEOR在精确匹配基础上引入词干还原和同义词匹配,并计算碎片化惩罚,从而比单纯BLEU更能反映语义等价性。你需要完成一个可独立运行的Python实现,输入为候选文本与参考文本,输出METEOR分数。

核心实现

import re
from collections import Counter
from nltk.stem import PorterStemmer
from nltk.corpus import wordnet

stemmer = PorterStemmer()

def tokenize(text):
    return re.findall(r'\b\w+\b', text.lower())

def get_synonyms(word):
    syns = set()
    for syn in wordnet.synsets(word):
        for lemma in syn.lemmas():
            syns.add(lemma.name().lower().replace('_', ' '))
    return syns

def align_words(cand_tokens, ref_tokens):
    """贪心对齐:优先精确匹配,其次词干匹配,最后同义词匹配"""
    cand_matched = [False] * len(cand_tokens)
    ref_matched = [False] * len(ref_tokens)
    stem_cand = [stemmer.stem(w) for w in cand_tokens]
    stem_ref = [stemmer.stem(w) for w in ref_tokens]
    syn_cache = {}

    # 阶段1:精确匹配
    for i, cw in enumerate(cand_tokens):
        for j, rw in enumerate(ref_tokens):
            if not cand_matched[i] and not ref_matched[j] and cw == rw:
                cand_matched[i] = True
                ref_matched[j] = True
                break

    # 阶段2:词干匹配
    for i, cs in enumerate(stem_cand):
        if cand_matched[i]:
            continue
        for j, rs in enumerate(stem_ref):
            if not ref_matched[j] and cs == rs:
                cand_matched[i] = True
                ref_matched[j] = True
                break

    # 阶段3:同义词匹配
    for i, cw in enumerate(cand_tokens):
        if cand_matched[i]:
            continue
        if cw not in syn_cache:
            syn_cache[cw] = get_synonyms(cw)
        for j, rw in enumerate(ref_tokens):
            if not ref_matched[j] and rw in syn_cache[cw]:
                cand_matched[i] = True
                ref_matched[j] = True
                break

    return cand_matched, ref_matched

def meteor_score(candidate, reference, alpha=0.9, beta=3.0, gamma=0.5):
    cand_tokens = tokenize(candidate)
    ref_tokens = tokenize(reference)

    if not cand_tokens or not ref_tokens:
        return 0.0

    cand_matched, ref_matched = align_words(cand_tokens, ref_tokens)
    m = sum(cand_matched)
    if m == 0:
        return 0.0

    # 准确率与召回率
    precision = m / len(cand_tokens)
    recall = m / len(ref_tokens)
    if precision + recall == 0:
        return 0.0
    fmean = (10 * precision * recall) / (recall + 9 * precision)

    # 碎片化惩罚:统计匹配词块数
    chunks = 0
    in_chunk = False
    for i in range(len(cand_tokens)):
        if cand_matched[i]:
            if not in_chunk:
                chunks += 1
                in_chunk = True
        else:
            in_chunk = False

    if chunks > 0:
        frag_penalty = gamma * (chunks / m) ** beta
    else:
        frag_penalty = 0.0

    return (1 - frag_penalty) * fmean

# 示例调用
if __name__ == "__main__":
    cand = "The cat sat on the mat"
    ref = "A cat is sitting on a mat"
    score = meteor_score(cand, ref)
    print(f"METEOR score: {score:.4f}")

依赖与运行

pip install nltk
python -c "import nltk; nltk.download('wordnet'); nltk.download('omw-1.4')"
python meteor.py

验证方法

运行上述示例,预期输出约为 METEOR score: 0.5000(精确值取决于同义词匹配结果)。判定标准:

  • 候选与参考完全相同时,输出1.0;
  • 无语义重叠时输出0.0;
  • 同义词替换(如“car”与“automobile”)应获得非零分数;
  • 词序打乱但词集相同,分数应低于完全匹配但高于随机词序。
METEOR指标计算流程 候选文本 "The cat sat..." 参考文本 "A cat is..." 分词与词干还原 tokenize + PorterStemmer 三阶段贪心对齐 精确匹配 词干匹配 同义词匹配 Fmean计算 + 碎片化惩罚 METEOR = (1 - γ·(chunks/m)³) · Fmean 分数

关键设计说明

本实现采用贪心对齐策略,按精确→词干→同义词三级顺序匹配,确保每个参考词最多匹配一个候选词。碎片化惩罚通过统计连续匹配块数计算,惩罚词序混乱。同义词匹配依赖WordNet,需提前下载语料。该实现覆盖METEOR核心计算逻辑,适用于短文本质量评估场景。