【NLP】【四】jieba源碼分析之詞性標註 原

【一】詞性標註

詞性標註分爲2部分,首先是分詞,然後基於分詞結果做詞性標註。

【二】jieba的詞性標註代碼流程詳解

1. 代碼位置

jieba/posseg/_init_.py

2. 流程分析

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等

 

【三】總結

jieba總體而言,包含如下三個功能:分詞、詞性標註、關鍵字提取。使用的都是傳統的方法,如基於詞典前綴的匹配、基於HMM模型對未登錄詞進行分割與詞性標註、基於TF-IDF和TextRank進行關鍵字提取。這三大功能,全都離不開jieba基於語料庫統計出來的詞典,包括詞頻、詞性、HMM模型參數(狀態轉移概率矩陣、發射概率矩陣、初始狀態概率向量)。

要想使用jieba得到好的分詞效果,需要替換自己的詞典,訓練自己的HMM參數,而這些,基本都是基於語料庫統計得到的。

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