基于Hanlp--词典分词:切分算法

1 词典加载

from pyhanlp import *
def load_dictionary():
    """
    加载Hanlp中的Mini词库
    :return:一个set形式的词库
    """
    IOUtil = JClass('com.hankcs.hanlp.corpus.io.IOUtil')
    path = HanLP.Config.CoreDictionaryPath.replace('.txt','.mini.txt')
    dic = IOUtil.loadDictionary([path])
    return set(dic.keySet())

这里使用的是hanlp提供的词库,后面的切分算法也可以使用自己的词典,hanlp相关的配置安装可以参考

hanlp安装配置

2 完全切分算法

    完全切分指的是,找出一段文本中的所有单词。这并不是标准意义上的分词,有些人将这个过程误称为分词,其实不准确。

    不考虑效率的话,朴素的完全切分算法其实很简单。只要遍历文本中连续序列,查询该序列是否在字典中即可。定义词典为dic,文本为txt,当前处理位置为i,代码如下:

def fully_segment(txt,dic):
    res = []
    for i in range(len(txt)):
        for j in range(i+1,len(txt)+1):
            tmp = txt[i:j]
            if(tmp in dic):
                res.append(tmp)
    return res

调用样例:

a = load_dictionary()
aa = '就读北京大学'
fully_segment(aa,a)

#结果:['就', '就读', '读', '北', '北京', '北京大学', '京', '大', '大学', '学']

3 最长匹配算法

上面的输出并不是中文分词,我们更需要那种有意义的词语序列,而不是所有出现在词典中的单词所构成的链表。比如,我们希望“北京大学”成为一整个词,而不是“北京”+“大学”之类的碎片。为了达到这个目的,需要完善一下我们的规则,考虑到越长的单词表达的意义越丰富,于是我们定义单词越长优先级越高。具体说来,就是在某个下标为起点递增查词的过程中,优先输出更长的单词,这种规则被称为最长匹配算法。该下标的扫描顺序如果从前往后,称为正向最长匹配,反之则称逆向最长匹配。

3.1 正向最长匹配

def forward_segment(txt,dic):
    res = []
    i = 0
    while(i<len(txt)):
        maxl = 0
        r = ''
        for j in range(i+1,len(txt)+1):
            tmp = txt[i:j]
            if(tmp in dic):
                r = tmp
                maxl = j
        i = maxl
        res.append(r)
    return res

调用样例和结果展示:

forward_segment(aa,a)

#结果:['就读', '北京大学']

3.2 逆向最长匹配

def backward_segment(txt,dic):
    res = []
    i = len(txt)
    while(i > 0):
        minl = 0
        j = i - 1
        r = ''
        while(j >= 0):
            tmp = txt[j:i]
            if(tmp in dic):
                r = tmp
                minl = j
            j-=1
        i = minl
        res.append(r)
    res.reverse()
    return res

调用样例和结果展示:

backward_segment(aa,a)

#结果:['就读', '北京大学']

3.3 双向最长匹配

提出这种方法的原因是为了综合上面两种最长匹配算法的优势。这是一种融合两种匹配方法的复杂规则:

  1. 同时执行正向和逆向最长匹配,若两者的词数不同,则返回词数更少的那一个。
  2. 否则,返回两者中单字更少的那一个。当单字数也相同时,优先返回逆向最长匹配的结果。
def bidrectional_segment(txt,dic):
    f = forward_segment(txt,dic)
    b = backward_segment(txt,dic)
    lf = len(f)
    lb = len(b)
    return b if(lf>=lb) else f

调用和结果样例:

bb = '研究生命起源'
bidrectional_segment(bb,a)

#结果:['研究', '生命', '起源']

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章