jieba分词之二、cut

jieba.posseg.cut(sentence)是initialize操作之后分词程序的入口

__cut_internal(sentence)函数内部定义了四个正则表达式
re_han = re.compile(ur"([\u4E00-\u9FA5a-zA-Z0-9+#&\._]+)")
re_skip = re.compile(ur"(\r\n|\s)")
re_eng = re.compile(ur"[a-zA-Z0-9]+")
re_num = re.compile(ur"[\.0-9]+")
函数内部语句blocks = re_han.split(sentence)把整个句子多个部分blk,若blk满足re_han模式,说明是有汉字的字符串,然后调用__cut_DAG(blk),构建字符串DAG和route

jieba分词之二、cut_第1张图片

1、get_DAG(sentence)函数

DAG是有向无环图,结巴分词中的DAG的数据结构是dict,元素的key是int,value是int列表

下面部分内容引用自http://www.xuebuyuan.com/1547637.html

举一个例子,比如sentence 是 "国庆节我在研究结巴分词",对应生成的DAG是这样的:
{0: [0, 1, 2], 1: [1], 2: [2], 3: [3], 4: [4], 5: [5, 6], 6: [6], 7: [7, 8], 8: [8], 9: [9, 10], 10: [10]}
其中的数字表示每个汉字在sentence中的位置,所以0:[0,1,2] 表示 在trie 树中,"国"开头的词语中对应于该 sentence 有三种匹配情况:国,国庆,国庆节;分别对应3条有向图的路径:0->1->2->3,0->2->3,0->3。


initialize中生成的FREQ是一个dict类型的变量,它用来保存dict.txt中每个词语的频度打分,打分的公式是 log(float(v)/total),其中v就是被打分词语的频度值。
目标就很明确了:我们已经有了sentence的DAG和sentence中每个词语的频度得分,要在所有的路径中找出一条路径使频度得分的总和最大,这同时也是动态规划的一个典型应用。

2、calc(sentence,DAG,idx,route)函数
calc函数更新route
作者实现的代码如下:
def calc(sentence,DAG,idx,route):
    N = len(sentence)
    route[N] = (0.0,'')
    for idx in xrange(N-1,-1,-1):
        candidates = [ ( FREQ.get(sentence[idx:x+1],min_freq) + route[x+1][0],x ) for x in DAG[idx] ]
        route[idx] = max(candidates)
这是一个自底向上的动态规划,从sentence的最后一个字开始倒序遍历每个分词方式的得分(必须是倒序,正序不行,大家可以思考下为什么)。然后将得分最高的情况以(频度得分值,词语最后一个字的位置)这样的tuple保存在route中。(注:从代码上看idx是一个无用的参数~)


3、__cut_DAG(sentence)函数的源码

def __cut_DAG(sentence):
    DAG = jieba.get_DAG(sentence)
    route ={}    
    jieba.calc(sentence,DAG,0,route=route) #根据语料库和频度打分机制生成一个初步的分词结果

    x = 0
    buf =u''
    N = len(sentence)
    while x         y = route[x][1]+1
        l_word = sentence[x:y]
        if y-x==1:  #单个的字符会把它放到buf中
            buf+= l_word
        else:         #l_word的长度大于1
            if len(buf)>0:
                if len(buf)==1:                    
                    yield pair(buf,word_tag_tab.get(buf,'x')) ###
                    buf=u''
                else:
                    ######################################################################
                    if (buf not in jieba.FREQ): ### buf不在jieba.FREQ中
                        regognized = __cut_detail(buf) ### __cut_detail 处理未登录词
                        for t in regognized:
                            yield t
                    else:
                        for elem in buf:
                            yield pair(elem,word_tag_tab.get(elem,'x')) ###
                    buf=u''
                    ######################################################################
            yield pair(l_word,word_tag_tab.get(l_word,'x')) ###l_word的输出
        x =y

  ###边界问题处理(细节)


4.__cut_detail(sentence)函数
__cut_detail(sentence)函数内部定义了四个正则表达式
re_han = re.compile(ur"([\u4E00-\u9FA5]+)") 
re_skip = re.compile(ur"([\.0-9]+|[a-zA-Z0-9]+)")
re_eng = re.compile(ur"[a-zA-Z0-9]+")
re_num = re.compile(ur"[\.0-9]+")
函数内部语句blocks = re_han.split(sentence)把整个句子多个部分blk,若blk满足re_han模式,说明blk是汉字串,然后调用__cut(blk)


5.__cut(sentence)函数

你可能感兴趣的:(jieba分词)