jieba分詞有多種模式可供選擇。可選的模式包括:python
全切分模式正則表達式
精確模式算法
搜索引擎模式函數
同時也提供了HMM模型的開關。搜索引擎
其中全切分模式就是輸出一個字串的全部分詞,spa
精確模式是對句子的一個機率最佳分詞,code
而搜索引擎模式提供了精確模式的再分詞,將長詞再次拆分爲短詞。索引
效果大抵以下:ip
# encoding=utf-8 import jieba seg_list = jieba.cut("我來到北京清華大學", cut_all=True) print("Full Mode: " + "/ ".join(seg_list)) # 全模式 seg_list = jieba.cut("我來到北京清華大學", cut_all=False) print("Default Mode: " + "/ ".join(seg_list)) # 精確模式 seg_list = jieba.cut("他來到了網易杭研大廈") # 默認是精確模式 print(", ".join(seg_list)) seg_list = jieba.cut_for_search("小明碩士畢業於中國科學院計算所,後在日本京都大學深造") # 搜索引擎模式 print(", ".join(seg_list))
的結果爲utf-8
【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學 【精確模式】: 我/ 來到/ 北京/ 清華大學 【新詞識別】:他, 來到, 了, 網易, 杭研, 大廈 (此處,「杭研」並無在詞典中,可是也被Viterbi算法識別出來了) 【搜索引擎模式】: 小明, 碩士, 畢業, 於, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, 後, 在, 日本, 京都, 大學, 日本京都大學, 深造
其中,新詞識別即用HMM模型的Viterbi算法進行識別新詞的結果。
值得詳細研究的模式是精確模式,以及其用於識別新詞的HMM模型和Viterbi算法。
在載入詞典以後,jieba分詞要進行分詞操做,在代碼中就是核心函數jieba.cut()
,代碼以下:
def cut(self, sentence, cut_all=False, HMM=True): ''' The main function that segments an entire sentence that contains Chinese characters into seperated words. Parameter: - sentence: The str(unicode) to be segmented. - cut_all: Model type. True for full pattern, False for accurate pattern. - HMM: Whether to use the Hidden Markov Model. ''' sentence = strdecode(sentence) if cut_all: re_han = re_han_cut_all re_skip = re_skip_cut_all else: re_han = re_han_default re_skip = re_skip_default if cut_all: cut_block = self.__cut_all elif HMM: cut_block = self.__cut_DAG else: cut_block = self.__cut_DAG_NO_HMM blocks = re_han.split(sentence) for blk in blocks: if not blk: continue if re_han.match(blk): for word in cut_block(blk): yield word else: tmp = re_skip.split(blk) for x in tmp: if re_skip.match(x): yield x elif not cut_all: for xx in x: yield xx else: yield x
其中,
docstr中給出了默認的模式,精確分詞 + HMM模型開啓。
第12-23行進行了變量配置。
第24行作的事情是對句子進行中文的切分,把句子切分紅一些只包含能處理的字符的塊(block),丟棄掉特殊字符,由於一些詞典中不包含的字符可能對分詞產生影響。
24行中re_han默認值爲re_han_default,是一個正則表達式,定義以下:
# \u4E00-\u9FD5a-zA-Z0-9+#&\._ : All non-space characters. Will be handled with re_han re_han_default = re.compile("([\u4E00-\u9FD5a-zA-Z0-9+#&\._]+)", re.U)
能夠看到諸如空格、製表符、換行符之類的特殊字符在這個正則表達式被過濾掉。
25-40行使用yield實現了返回結果是一個迭代器,即文檔中所說:
jieba.cut 以及 jieba.cut_for_search 返回的結構都是一個可迭代的 generator,可使用 for 循環來得到分詞後獲得的每個詞語(unicode)
其中,31-40行,若是遇到block是很是規字符,就正則驗證一下直接輸出這個塊做爲這個塊的分詞結果。如標點符號等等,在分詞結果中都是單獨一個詞的形式出現的,就是這十行代碼進行的。
關鍵在28-30行,若是是可分詞的block,那麼就調用函數cut_block
,默認是cut_block = self.__cut_DAG
,進行分詞
__cut_DAG
的做用是按照DAG,即有向無環圖進行切分單詞。其代碼以下:
def __cut_DAG(self, sentence): DAG = self.get_DAG(sentence) route = {} self.calc(sentence, DAG, route) x = 0 buf = '' N = len(sentence) while x < N: y = route[x][1] + 1 l_word = sentence[x:y] if y - x == 1: buf += l_word else: if buf: if len(buf) == 1: yield buf buf = '' else: if not self.FREQ.get(buf): recognized = finalseg.cut(buf) for t in recognized: yield t else: for elem in buf: yield elem buf = '' yield l_word x = y if buf: if len(buf) == 1: yield buf elif not self.FREQ.get(buf): recognized = finalseg.cut(buf) for t in recognized: yield t else: for elem in buf: yield elem
對於一個sentence,首先 獲取到其有向無環圖DAG,而後利用dp對該有向無環圖進行最大機率路徑的計算。
計算出最大機率路徑後迭代,若是是登陸詞,則輸出,若是是單字,將其中連在一塊兒的單字找出來,這些多是未登陸詞,使用HMM模型進行分詞,分詞結束以後輸出。
至此,分詞結束。
其中,值得跟進研究的是第2行獲取DAG
,第4行計算最大機率路徑
和第20和34行的使用HMM模型進行未登陸詞的分詞
,在後面的文章中會進行解讀。
DAG = self.get_DAG(sentence) ... self.calc(sentence, DAG, route) ... recognized = finalseg.cut(buf)