1. 程式人生 > >結巴分詞1.8.2版本原始碼解析(一)

結巴分詞1.8.2版本原始碼解析(一)

概要說明:結巴分詞是基於python的開源分詞工具。在其根目錄下的結構為
.
|--analyse
|--finalseg
|--posseg
|--__init__.py
|--__main__.py
|--_compat.py
|--dict.txt
其中analyse是對分詞結果進行分析的資料夾,提供了TF-IDF演算法和textrank演算法。finalseg提供了vertbit演算法需要的初始矩陣。posseg是進行詞性標註的程式碼。
結巴分詞的核心程式碼在根目錄下的__init__.py中。


官方文件中關於演算法的說明:
1、基於Trie樹結構實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖(DAG)
2、採用了動態規劃查詢最大概率路徑, 找出基於詞頻的最大切分組合
3、對於未登入詞,採用了基於漢字成詞能力的HMM模型,使用了Viterbi演算法


__init__.py:
全域性變數:


DICTIONARY = "dict.txt"   #預設字典名
DICT_LOCK = threading.RLock() #執行緒鎖
FREQ = {}  # to be initialized#tire樹
total = 0#計數器
user_word_tag_tab = {}
initialized = False#標記是否初始化
pool = None
tmp_dir = None

_curpath = os.path.normpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))#得到當前絕對路徑

log_console = logging.StreamHandler(sys.stderr) #日誌相關

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(log_console)


關鍵函式:
1、函式名:gen_pfdict(f_name) 這個是演算法說明1中基於Trie樹結構實現高效的詞圖掃描,但是通過程式碼可以看出這裡所謂的Tire樹,只是是一個字典,並且沒有巢狀。
通過程式碼54-57行看出這裡對每一個詞從第一個字開始逐字增加判斷是否包含在Tire樹(字典)中。

2、函式名:initialize(dictionary=None)。這裡是對程式的初始化,主要工作是載入詞典,這裡運用了快取技術(tempfile庫),還沒看這個庫(mark)。


3、函式名:get_DAG(sentence) 函式功能為把輸入的句子生成有向無環圖。測試sentence="英語單詞的詞形變化主要是增加前後綴"。
執行結果為:{"0": [0, 1, 3], "1": [1], "2": [2, 3], "3": [3], "4": [4], "5": [5, 6, 8], "6": [6, 7], "7": [7, 8], "8": [8], "9": [9, 10], "10": [10, 11], "11": [11], "12": [12, 13], "13": [13], "14": [14, 15], "15": [15, 16], "16": [16]}
這個字典即為DAG,key為字所在的位置,value為從字開始能在FREQ中的匹配到的詞末尾位置所在的list。句子中的第一個字為'英',所在位置即key為0,
value為[0, 1, 3],表示'英'、'英語'、'英語單詞'可以再FREQ中找到。

4、函式名:__cut_all(sentence) 函式功能就是結巴分詞的全模式分詞,作用即把DAG中的結果全部顯示出來。這裡使用了yield來迭代返回結果。


5、函式名:__cut_DAG_NO_HMM(sentence)。函式功能:對sentence進行不加hmm的精確分詞。精確分詞是在全分詞的基礎上計算各種路徑的概率,選取概率最大的路徑。
函式calc(sentence, DAG, route)就是計算概率的過程。其中語句 xrange(N - 1, -1, -1)是從句子的末尾開始計算,
route[idx] = max((log(FREQ.get(sentence[idx:x + 1]) or 1) -
                          logtotal + route[x + 1][0], x) for x in DAG[idx])
max函式返回的是一個元組,計算方法是log(freq/total)+後一個字得到的最大概率路徑的概率。這裡即為動態規劃查詢最大概率路徑。注意的是動態規劃的方向是
從後往前。

6、函式名:__cut_DAG(sentence)功能是對語句進行精確分詞並且使用HMM模型,對比函式__cut__DAG_NO_HMM(sentence)的主要區別是有一個未登入詞的識別功能。程式碼為
if not FREQ.get(buf):
        recognized = finalseg.cut(buf)
        for t in recognized:
            yield t
可以看到呼叫的是finalseg.cut()函式

7、函式名:cut(sentence, cut_all=False, HMM=True) 這裡原始碼中帶有註釋,函式根據引數的不同調用上面不同的函式4、5、6

測試程式碼:

#coding=utf-8
#author:zhangyang
#2015-5-27
#程式用於結巴分詞根目錄__init__.py測試


from __future__ import absolute_import, unicode_literals
import os
from math import log
import json

dirname = os.path.dirname(__file__)
print dirname
cwd=os.getcwd()
print cwd
ww=os.path.join(os.getcwd(), os.path.dirname(__file__))
print ww
FREQ={}
total=0

def gen_pfdict(f_name):
    lfreq = {}
    ltotal = 0
    with open(f_name, 'rb') as f:
        lineno = 0
        for line in f.read().rstrip().decode('utf-8').splitlines():
            lineno += 1
            try:
                word, freq = line.split(' ')[:2]
                freq = int(freq)
                lfreq[word] = freq
                ltotal += freq
                for ch in xrange(len(word)):
                    wfrag = word[:ch + 1]
                    if wfrag not in lfreq:
                        lfreq[wfrag] = 0
            except ValueError as e:
                logger.debug('%s at line %s %s' % (f_name, lineno, line))
                raise e
    return lfreq, ltotal

def get_DAG(sentence):
    global FREQ
    DAG = {}
    N = len(sentence)
    for k in xrange(N):
        tmplist = []
        i = k
        frag = sentence[k]
        while i < N and frag in FREQ:
            if FREQ[frag]:
                tmplist.append(i)
            i += 1
            frag = sentence[k:i + 1]
        if not tmplist:
            tmplist.append(k)
        DAG[k] = tmplist
    return DAG

def calc(sentence, DAG, route):
    N = len(sentence)
    route[N] = (0, 0)
    logtotal = log(total)
    for idx in xrange(N - 1, -1, -1):
        route[idx] = max((log(FREQ.get(sentence[idx:x + 1]) or 1) -
                          logtotal + route[x + 1][0], x) for x in DAG[idx])
	print json.dumps(route)
	#for k,v in route.items():
		#print k,str(v)

def main():
	global FREQ,total
	dictfile='./dict.txt'
	FREQ,total=gen_pfdict(dictfile)
	print "total frequnce is "+str(total)
	print "dict length is "+str(len(FREQ))
	#i=0
	#g = lambda m: '\n'.join([ '%s=%d'%(k, v) for k, v in m.items() ])
	sent="英語單詞很難記憶"
	dag=get_DAG(sent)
	print json.dumps(dag)
	route={}
	calc(sent,dag,route)
	N=len(sent)
	x=0
	while x < N:
		y = route[x][1] + 1
		print y
		lword = sent[x:y]
		print lword
		x=y

if __name__=='__main__':
	main()


相關推薦

結巴1.8.2版本原始碼解析()

概要說明:結巴分詞是基於python的開源分詞工具。在其根目錄下的結構為 . |--analyse |--finalseg |--posseg |--__init__.py |--__main__.py |--_compat.py |--dict.txt 其中analyse

結巴.net core 2.0版 nuget發布過程

core param inf 文件 pos 成功 搜索 ros uri 最近用到分詞考慮很久,選用了結巴分詞,原因見博客Lucene.net(4.8.0) 學習問題記錄五: JIEba分詞和Lucene的結合,以及對分詞器的思考 既然選好了,難就開始行動吧 。 查了.net

結巴資料彙編】結巴中文原始碼分析(2)

如下演算法實現分詞: 1. 基於字首詞典實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖 (DAG); 作者這個版本中使用字首字典實現了詞庫的儲存(即dict.txt檔案中的內容),而棄用之前版本的trie樹儲存詞庫,想想也是,python中實現的trie樹是基於dict型

cocos creator 大廳+子游戲模式探討(creator版本1.8.2

之前一直從事android開發,接觸cocos creator不久。近期公司安排我研究大廳子游戲模式的熱更新,前後花了近一週時間,在論壇上查資料,請教大神,期間得到了一些幫助,在此很感謝cocos中文論

【資料彙編】結巴中文官方文件和原始碼分析系列文章

作者:白寧超 2016年11月23日16:49:36 摘要:結巴中文分詞的特點如下:支援三種分詞模式:(精確模式,試圖將句子最精確地切開,適合文字分析;全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提高召回率,適合

【我的區塊鏈之路】- 以太坊原始碼剖析之Geth 1.8.14版本挖礦邏輯調整

今天為什麼寫這個文章呢,首先,前段時間有朋友問過我,說現在geth的1.8.14版本的程式碼和網上各路大神們的分析不一樣了。我就趕緊看了下,確實,親的geth程式碼中的mine部分的邏輯有所改動,想必看過原始碼的都知道,之前的miner真正挖礦是由worker把所需挖礦的

結巴原始碼解析(二)

本篇分兩部分,一、補充說明動態規劃求最大概率路徑的過程;二、使用viterbi演算法處理未登入詞。 一、動態規劃求最大概率路徑補充從全模式中看出一句話有多種劃分方式,那麼哪一種是好的劃分方式,最大概率路徑認為,如果某個路徑下詞的聯合概率最大,那麼這個路徑為最好的劃分方式。

起步:Proteus 8 仿真 Arduino 1.8.2

準備 sel 9.png tieba nbsp 自己 aid 新版 添加 一、環境準備 1、從Arduino官網或中文社區下載並安裝 Arduino IDE 當前最新版1.8.2:http://www.arduino.cn/thread-5838-1-1.html

avro 1.8.2 (js)

score record name str mage readme.md 目錄 提示 清華大學 5月15日發布的avro 1.8.2 已經包含了js版代碼。 清華大學鏡像地址: https://mirrors.tuna.tsinghua.edu.cn/apache/avro

Python 結巴 關鍵詞抽取分析

等於 範圍 分類問題 urn post bre 依然 信息檢索 有意 關鍵詞抽取就是從文本裏面把跟這篇文檔意義最相關的一些詞抽取出來。這個可以追溯到文獻檢索初期,當時還不支持全文搜索的時候,關鍵詞就可以作為搜索這篇論文的詞語。因此,目前依然可以在論文中看到關鍵詞這一項。

Python中結巴使用手記

img 3年 方法封裝 python token sys.path 裝飾 arp mage 結巴分詞方法封裝類 from __future__ import unicode_literals import sys sys.path.append("../")

python中文,使用結巴對python進行

php 分詞 在采集美女站時,需要對關鍵詞進行分詞,最終采用的是python的結巴分詞方法.中文分詞是中文文本處理的一個基礎性工作,結巴分詞利用進行中文分詞。其基本實現原理有三點:基於Trie樹結構實現高效的詞圖掃描,生成句子中漢字所有可能成詞情況所構成的有向無環圖(DAG)采用了動態規劃查找最大概率

jieba結巴

返回 int 使用 error import arch 豆瓣 但是 定義 pip install jieba安裝jieba模塊如果網速比較慢,可以使用豆瓣的Python源:pip install -i https://pypi.douban.com/simple/ jieb

Flink 1.4.2 版本踩過的坑

0x1 摘要 最近業務要實時統計半小時維度的UV、PV資料,經過調研準備用Flink時間窗來實現,主要是Flink對eventTime的支援,可以做到更精準的統計,由於第一次嘗試使用Flink,所以過程中遇到不少問題,記錄下來方便後續查閱。 0x2 執行計劃輸出JSON問題 Flink對

python 結巴(jieba)詳解

【轉自:https://www.cnblogs.com/jackchen-Net/p/8207009.html】 “結巴”中文分詞:做最好的 Python 中文分片語件 "Jieba" (Chinese for "to stutter") Chinese text segmentation:

ossutil釋出1.4.2版本,支援上傳或複製檔案目錄指定儲存型別,支援訪問請求者付費模式的Bucket

ossutil 1.4.2 Release Note lscp命令:支援訪問開啟“請求者付費模式”的Bucket cp命令:上傳、複製檔案或目錄時,支援設定儲存型別 cp命令:上傳下載時,顯示傳輸速度 cp命令:Window版本支援斷點續傳(Linux、Mac版本已經支援) os

網際網路一站式框架 sumk 釋出 1.8.5 版本

         sumk 的定位是提供一個類似於 spring boot 的輕量級網際網路框架。它的生命線是開發速度和對網際網路天然支援,比如分散式session、資料庫讀寫分離、微服務、資料快取及重新整理等。本次更新的主要內容有: 工具化,

Jaeger 1.8.2 釋出,Uber 開源的分散式追蹤系統

   Jaeger 是 Uber 開源的分散式追蹤系統,靈感來自於 Dapper 和 OpenZipkin ,現已加入 CNCF 基金會。它可以用於監視基於微服務的體系結構:  分散式上下文傳播

spring4.1.8初始化原始碼學習三部曲之二:setConfigLocations方法

本章是學習spring4.1.8初始化原始碼的第二篇,前一章《spring4.1.8初始化原始碼學習三部曲之一:AbstractApplicationContext構造方法》對AbstractApplicationContext的初始化做了分析,本章我們聚焦

spring4.1.8初始化原始碼學習三部曲之一:AbstractApplicationContext構造方法

這個demo的原始碼可以在github下載,地址和連結資訊如下表所示: 名稱 連結 備註 專案主頁 https://github.com/zq2599/blog_demos 該專案在GitHub上的主頁 git倉庫地址(https)