查看原文
其他

NLP.TM[35] | 纠错:pycorrector的候选排序

机智的叉烧 CS的陋室 2022-08-08

【NLP.TM】


本人有关自然语言处理和文本挖掘方面的学习和笔记,欢迎大家关注。


往期回顾


有关pycorrector这块,之前讲了错误检测和召回,这回讲讲最后的一步,排序。有关pycorrector里面的排序内容其实比较简单,其实就这是基于ppl来做排序。来看看具体怎么做的。

def get_lm_correct_item(self, cur_item, candidates, before_sent, after_sent, threshold=57):
    """
    通过语言模型纠正字词错误
    :param cur_item: 当前词
    :param candidates: 候选词
    :param before_sent: 前半部分句子
    :param after_sent: 后半部分句子
    :param threshold: ppl阈值, 原始字词替换后大于该ppl值则认为是错误
    :return: str, correct item, 正确的字词
    """

    result = cur_item
    if cur_item not in candidates:
        candidates.append(cur_item)

    ppl_scores = {i: self.ppl_score(list(before_sent + i + after_sent)) for i in candidates}
    sorted_ppl_scores = sorted(ppl_scores.items(), key=lambda d: d[1])

    # 增加正确字词的修正范围,减少误纠
    top_items = []
    top_score = 0.0
    for i, v in enumerate(sorted_ppl_scores):
        v_word = v[0]
        v_score = v[1]
        if i == 0:
            top_score = v_score
            top_items.append(v_word)
        # 通过阈值修正范围
        elif v_score < top_score + threshold:
            top_items.append(v_word)
        else:
            break
    if cur_item not in top_items:
        result = top_items[0]
    return result

从代码中能看到,其实长度就不是很长,核心代码也不是很长。

  • 求全局ppl。
  • 按照ppl排序。
  • 最后确认是否纠正。

全局ppl

前面其实也有算分数,这里其实是算的是全局的ppl,毕竟纠错的最终目标就是让整个句子正确,这里的评价标准就是整个句子更加能“成句”。

ppl_scores = {i: self.ppl_score(list(before_sent + i + after_sent)) for i in candidates}

把修改部分的结果和原句拼接回去然后计算整个句子的混淆程度。

def ppl_score(self, words):
    """
    取语言模型困惑度得分,越小句子越通顺
    :param words: list, 以词或字切分
    :return:
    """

    self.check_detector_initialized()
    return self.lm.perplexity(' '.join(words))

按照ppl排序

其实就是一行代码的事情:

sorted_ppl_scores = sorted(ppl_scores.items(), key=lambda d: d[1])

确认是否纠正

这里有一个比较有意思的事情,就是为了防止过纠,作者要求ppl必须超过原句一定距离,才让他纠。

# 增加正确字词的修正范围,减少误纠
top_items = []
top_score = 0.0
for i, v in enumerate(sorted_ppl_scores):
    v_word = v[0]
    v_score = v[1]
    if i == 0:
        top_score = v_score
        top_items.append(v_word)
    # 通过阈值修正范围
    elif v_score < top_score + threshold:
        top_items.append(v_word)
    else:
        break
if cur_item not in top_items:
    result = top_items[0]
return result

其实纠错的排序的基线就是ppl算全局的效果,没有想到的是为了保证效果可靠性,防止过纠,所以加了一个阈值的约束。

小结

一连3篇讨论pycorrector方面基本纠错的讲解已经结束。这应该业内开源比较完整的一套方法了,简单的甚至可以直接拿来做基线,当然特殊场景可能需要一些调整,但是里面的内容是非常有参考意义的,未来需要优化也可以在调整架构后形成插件的模式加入,非常方便。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存