【NLP】【四】jieba源码分析之词性标注

【一】词性标注python

词性标注分为2部分,首先是分词,而后基于分词结果作词性标注。正则表达式

【二】jieba的词性标注代码流程详解算法

1. 代码位置函数

jieba/posseg/_init_.pythis

2. 流程分析code

def cut(sentence, HMM=True):
    """
    Global `cut` function that supports parallel processing.

    Note that this only works using dt, custom POSTokenizer
    instances are not supported.
    """
    global dt
    # 该pool 默认为None
    if jieba.pool is None:
        # 调用POSTokenizer的cut接口进行词性标注
        for w in dt.cut(sentence, HMM=HMM):
            yield w
    else:
        parts = strdecode(sentence).splitlines(True)
        if HMM:
            result = jieba.pool.map(_lcut_internal, parts)
        else:
            result = jieba.pool.map(_lcut_internal_no_hmm, parts)
        for r in result:
            for w in r:
                yield w

能够看出,对于未登陆词,采用HMM模型进行分词与词性标注。接口

def __cut_internal(self, sentence, HMM=True):
        # 词典加载
        self.makesure_userdict_loaded()
        sentence = strdecode(sentence)
        # 中文正则表达式匹配
        blocks = re_han_internal.split(sentence)

        # 设置分词函数
        if HMM:
            cut_blk = self.__cut_DAG
        else:
            cut_blk = self.__cut_DAG_NO_HMM

        for blk in blocks:
            # 若是是中文,则调用分词接口进行分词与词性标注
            if re_han_internal.match(blk):
                for word in cut_blk(blk):
                    yield word
            else:
                tmp = re_skip_internal.split(blk)
                for x in tmp:
                    if re_skip_internal.match(x):
                        yield pair(x, 'x')
                    else:
                        for xx in x:
                            # 若是是数字,则使用m标注词性,因为number的n和u已经用于其余词性,所以使用m
                            if re_num.match(xx):
                                yield pair(xx, 'm')
                            # 若是是英文,标注为eng
                            elif re_eng.match(x):
                                yield pair(xx, 'eng')
                            # 不然,一概标注为x
                            else:
                                yield pair(xx, 'x')
# 对于未位登陆词,采用HMM模型进行词性标注
    def __cut_detail(self, sentence):
        blocks = re_han_detail.split(sentence)
        for blk in blocks:
            if re_han_detail.match(blk):
                # 使用HMM模型进行词性标注
                for word in self.__cut(blk):
                    yield word
            else:
                tmp = re_skip_detail.split(blk)
                for x in tmp:
                    if x:
                        if re_num.match(x):
                            yield pair(x, 'm')
                        elif re_eng.match(x):
                            yield pair(x, 'eng')
                        else:
                            yield pair(x, 'x')
def __cut(self, sentence):
        # 使用viterbi算法进行状态序列求解,这里的状态序列包含2部分
        # 一是:词的位置,而是词性。因为一词多性,所以须要计算出该词几率最大的词性
        prob, pos_list = viterbi(
            sentence, char_state_tab_P, start_P, trans_P, emit_P)
        begin, nexti = 0, 0

        for i, char in enumerate(sentence):
            pos = pos_list[i][0]
            if pos == 'B':
                begin = i
            elif pos == 'E':
                yield pair(sentence[begin:i + 1], pos_list[i][1])
                nexti = i + 1
            elif pos == 'S':
                yield pair(char, pos_list[i][1])
                nexti = i + 1
        if nexti < len(sentence):
            yield pair(sentence[nexti:], pos_list[nexti][1])

这里,依旧使用viterbi算法进行状态序列求解。这里就不分析了,算法流程和前面的未登陆词的分词一致。只是强调一点,这里的状态序列包含两部分:一是:字的位置,即BMES,而是词对应的词性,如 :n,a等ip

 

【三】总结it

jieba整体而言,包含以下三个功能:分词、词性标注、关键字提取。使用的都是传统的方法,如基于词典前缀的匹配、基于HMM模型对未登陆词进行分割与词性标注、基于TF-IDF和TextRank进行关键字提取。这三大功能,全都离不开jieba基于语料库统计出来的词典,包括词频、词性、HMM模型参数(状态转移几率矩阵、发射几率矩阵、初始状态几率向量)。io

要想使用jieba获得好的分词效果,须要替换本身的词典,训练本身的HMM参数,而这些,基本都是基于语料库统计获得的。

相关文章
相关标签/搜索