本文将介绍[b]baiziyu[/b] 所著的《HanLP 中的 N-最短路径分词》。本文部分内容有所调整,旨在为大家提供学习和交流的内容。
首先需要说明的是,HanLP 提供的接口中并未采用 N-最短路径分词器。作者在其官网上指出,这种分词器在实体识别方面略优于最短路径分词,但其运行速度较慢。对此,我个人有一些看法。N-最短路径分词与最短路径分词的主要区别在于,前者在每个节点考虑了 N 条最佳路径,并从中选择了最优的一条。然而,这种分词方式对于解决分词歧义问题可能有一定帮助,但对于未登录词的效果可能与最短路径分词差别不大。这只是我个人的推测,并没有实际验证。如果时间允许,我计划在新闻语料上对几种分词器进行对比评测。不过,这种评测的意义可能有限,因为不同类型的分词器在不同场景下的表现可能会有所不同。就像文本分类一样,目前还没有一种通用的分词器。
前面提到,在最短路径分词中,如果每个节点记录 N 条最短路径,那么这种方法被称为 N-最短路径算法。在 HanLP 中,通过 ViterbiSegment 和 NshortSegment 这两个类分别实现了最短路径分词和 N-最短路径分词。这里需要说明的是,之所以说是 N 条而不是 N 个,是因为算法会在每个字节点处计算所有到达该节点的路径,并按路径值排序。所谓“种”是指路径值的不同种类,因此当存在相同路径值的路径时,节点处保留的路径数量就会超过 N。
从继承关系图中可以看出,最短路径分词器和 N-最短路径分词器都继承自 WordBasedSegment 抽象类,这意味着它们在大类上都属于基于词语的分词器。接下来,我们还将介绍基于词典的分词器(极速词典分词器)和基于字符的分词器(感知机、条件随机场分词器)。抽象类 Segment 提供了分词方法 Seg,所有 HanLP 中实现的分词方法类都继承自该抽象类,并实现了抽象方法 segSentence。Seg 方法会对输入的文本进行处理,当文本较长时,它会自动将其拆分为多个短文本,然后利用多线程技术同步处理多个短文本,最后得到分词后的文本。对于短文本,Seg 方法则直接使用单线程处理。segSentence 方法会根据不同的分词方法对文本进行分词。这里,Seg 方法会调用 segSentence 方法,这是这两个方法之间的关系。以当前的 N-最短路径分词为例,segSentence 实现的就是 N-最短路径分词。如果是最短路径分词,则 segSentence 实现的就是最短路径分词。这些说明是为了让初学者更好地理解面向对象编程方法。
下面以句子“他说的确真实理”为例来说明 N-最短路径分词。程序的表现形式就是计算出如下的表格:
在这里,我们将 N-最短路径分词中的 N 设为 2,可以看到算法从“实”字开始就有多种最优路径,截取了前两名,最终得到两种分词结果。
至此,我们对 N-最短路径分词的介绍结束。接下来,我们总结一下 HanLP 中这两种分词方法的区别。
在节点上保留的最优路径前驱节点数量不同。具体来说,当某个节点存在两个以上的前驱节点时,N-最短路径一定会保留前 N 条路径的所有前驱节点,而最短路径只保留一条最短路径的前驱节点。
HanLP 在实现 N-最短路径方法时添加了数字和日期合并规则。
HanLP 的 N-最短路径方法最终返回的仍然是一个最优路径,并没有对前 N 个分词结果进行选择。尽管在某些节点处保留了多个候选前驱节点,但个人认为两者之间的差异可能不会太大。N-最短路径分词对分词歧义可能有效,但对于未登录词的效果可能并不显著。说到底,它仍然基于词典中单个词语的概率,其他文本信息都没有用到。
此外,我们注意到分词结果中包含了词性标注。关于词性标注,我们将在后续章节继续介绍,它与分词方法是两个独立的策略。程序会先进行分词,然后再根据用户配置进行词性标注。