開源中文分詞工具探析(三):Ansj
Ansj是由孫健(ansjsun)開源的一箇中文分詞器,為ICTLAS的Java版本,也採用了Bigram + HMM分詞模型(可參考我之前寫的文章):在Bigram分詞的基礎上,識別未登入詞,以提高分詞準確度。雖然基本分詞原理與ICTLAS的一樣,但是Ansj做了一些工程上的優化,比如:用DAT高效地實現檢索詞典、鄰接表實現分詞DAG、支援自定義詞典與自定義消歧義規則等。
【開源中文分詞工具探析】系列:
1. 前言
Ansj支援多種分詞方式,其中ToAnalysis為店長推薦款:
它在易用性,穩定性.準確性.以及分詞效率上.都取得了一個不錯的平衡.如果你初次嘗試Ansj如果你想開箱即用.那麼就用這個分詞方式是不會錯的.
因此,本文將主要分析ToAnalysis的分詞實現(基於ansj-5.1.0版本)。
ToAnalysis
繼承自抽象類org.ansj.splitWord.Analysis
,重寫了抽象方法getResult
。其中,分詞方法的依賴關係:ToAnalysis::parse -> Analysis::parseStr -> Analysis::analysisStr。analysisStr
方法就幹了兩件事:
- 按照消歧義規則分詞;
- 在此基礎上,按照核心詞典分詞;
analysisStr
方法的最後呼叫了抽象方法getResult
,用於對分詞DAG的再處理;所有的分詞類均重寫這個方法。為了便於理解ToAnalysis分詞,我用Scala 2.11重寫了:
import java.util import org.ansj.domain.{Result, Term} import org.ansj.recognition.arrimpl.{AsianPersonRecognition, ForeignPersonRecognition, NumRecognition, UserDefineRecognition} import org.ansj.splitWord.Analysis import org.ansj.util.TermUtil.InsertTermType import org.ansj.util.{Graph, NameFix} /** * @author rain */ object ToAnalysis extends Analysis { def parse(sentence: String): Result = { parseStr(sentence) } override def getResult(graph: Graph): util.List[Term] = { // bigram分詞 graph.walkPath() // 數字發現 if (isNumRecognition && graph.hasNum) new NumRecognition().recognition(graph.terms) // 人名識別 if (graph.hasPerson && isNameRecognition) { // 亞洲人名識別 new AsianPersonRecognition().recognition(graph.terms) // 詞黏結後修正打分, 求取最優路徑 graph.walkPathByScore() NameFix.nameAmbiguity(graph.terms) // 外國人名識別 new ForeignPersonRecognition().recognition(graph.terms) graph.walkPathByScore() } // 使用者自定義詞典的識別 new UserDefineRecognition(InsertTermType.SKIP, forests: _*).recognition(graph.terms) graph.rmLittlePath() graph.walkPathByScore() import scala.collection.JavaConversions._ val terms = graph.terms new util.ArrayList[Term](terms.take(terms.length - 1).filter(t => t != null).toSeq) } }
如果沒看懂,沒關係,且看下小節分解。
2. 分解
分詞DAG
分詞DAG是由類org.ansj.util.Graph
實現的,主要的欄位terms
為org.ansj.domain.Term
陣列。其中,類Term為DAG的節點,欄位包括:offe
首字元在句子中的位置、name
為詞,next
具有相同首字元的節點、from
前驅節點、score
打分。仔細看原始碼容易發現DAG是用鄰接表(array + linked-list)方式所實現的。
Bigram模型
Bigram模型對應於一階Markov假設,詞只與其前面一個詞相關,其對應的分詞模型:
\begin{equation}
\arg \max \prod_{i=1}^m P(w_{i} | w_{i-1}) = \arg \min - \sum_{i=1}^m \log P(w_{i} | w_{i-1})
\label{eq:bigram}
\end{equation}
對應的詞典為bigramdict.dic
,格式如下:
始##始@和 11
和@尚 1
和@尚未 1
世紀@末##末 3
...
初始狀態\(w_0\)對應於Bigram詞典中的“始##始”,\(w_{m+1}\)對應於“末##末”。Bigram分詞的實現為Graph::walkPath
函式:
/**
* bigram分詞
* @param relationMap 干涉性打分, key為"first_word \tab second_word", value為干涉性score值
*/
public void walkPath(Map<String, Double> relationMap) {
Term term = null;
// 給terms[0] bigram打分, 且前驅節點為root_term "始##始"
merger(root, 0, relationMap);
// 從第一個字元開始往後更新打分
for (int i = 0; i < terms.length; i++) {
term = terms[i];
while (term != null && term.from() != null && term != end) {
int to = term.toValue();
// 給terms[to] bigram打分, 更新最小非零score值對應的term為前驅
merger(term, to, relationMap);
term = term.next();
}
}
// 求解最短路徑
optimalRoot();
}
對條件概率\(P(w_{i} | w_{i-1})\)做如下的平滑處理:
\[ \begin{aligned} - \log P(w_{i} | w_{i-1}) & \approx - \log \left[ aP(w_{i-1}) + (1-a) P(w_{i}|w_{i-1}) \right] \\ & \approx - \log \left[ a\frac{f(w_{i-1})}{N} + (1-a) \left( \frac{(1-\lambda)f(w_{i-1},w_i)}{f(w_{i-1})} + \lambda \right) \right] \end{aligned} \]
其中,\(a=0.1\)為平滑因子,\(N=2079997\)為訓練語料中的總詞數,\(\lambda = \frac{1}{N}\)。上述平滑處理實現函式為MathUtil.compuScore
。
求解式子\eqref{eq:bigram}的最優解等價於求解分詞DAG的最短路徑。Ansj採用了類似於Dijkstra的動態規劃演算法(作者稱之為Viterbi演算法)來求解最短路徑。記\(G=(V,E)\)為分詞DAG,其中邊\((u,v) \in E\)滿足如下性質:
\[ v > u, \quad \forall \ (u,v) \in E \]
即DAG頂點的序號的順序與圖流向是一致的。這個重要的性質確保了(按Graph.terms[]
的index依次遞增)用動態規劃求解最短路徑的正確性。用\(d_i\)標記源節點到節點\(i\)的最短距離,則有遞推式:
\[ d_i = \min_{(j,i) \in E} \ \{ d_j+ b_{(j,i)} \} \]
其中,\(b_{(j,i)}\)為兩個相鄰詞的條件概率的負log值-$ \log P(w_{i} | w_{j})$。上述實現請參照原始碼Graph::walkPath
與Graph::optimalRoot
。
自定義詞典
Ansj支援自定義詞典分詞,是通過詞黏結的方式——如果相鄰的詞黏結後正好為自定義詞典中的詞,則可以被分詞——實現的。換句話說,如果自定義的詞未能完全覆蓋相鄰詞,則不能被分詞。舉個例子:
import scala.collection.JavaConversions._
val sentence = "倒模,替身算什麼?鍾漢良、ab《孤芳不自賞》摳圖來充數"
println(ToAnalysis.parse(sentence).mkString(" "))
// 倒/v 模/ng ,/w 替身/n 算/v 什麼/r ?/w 鍾漢良/nr 、/w ab/en 《/w 孤芳/nr 不/d 自賞/v 》/w 摳/v 圖/n 來/v 充數/v
DicLibrary.insert(DicLibrary.DEFAULT, "身算")
DicLibrary.insert(DicLibrary.DEFAULT, "摳圖")
println(ToAnalysis.parse(sentence).mkString(" "))
// 倒/v 模/ng ,/w 替身/n 算/v 什麼/r ?/w 鍾漢良/nr 、/w ab/en 《/w 孤芳/nr 不/d 自賞/v 》/w 摳圖/userDefine 來/v 充數/v
3. 參考資料
相關推薦
開源中文分詞工具探析(三):Ansj
Ansj是由孫健(ansjsun)開源的一箇中文分詞器,為ICTLAS的Java版本,也採用了Bigram + HMM分詞模型(可參考我之前寫的文章):在Bigram分詞的基礎上,識別未登入詞,以提高分詞準確度。雖然基本分詞原理與ICTLAS的一樣,但是Ansj做了一些工程上的優化,比如:用DAT高效地實現檢
開源中文分詞工具探析(六):Stanford CoreNLP
inf git deb seq 效果 analysis stream fix sps CoreNLP是由斯坦福大學開源的一套Java NLP工具,提供諸如:詞性標註(part-of-speech (POS) tagger)、命名實體識別(named entity recog
開源中文分詞工具探析(七):LTP
LTP是哈工大開源的一套中文語言處理系統,涵蓋了基本功能:分詞、詞性標註、命名實體識別、依存句法分析、語義角色標註、語義依存分析等。 【開源中文分詞工具探析】系列: 1. 前言 同THULAC一樣,LTP也是基於結構化感知器(Structured Perceptron, SP),以最大熵準則建模標註序列
開源中文分詞工具探析(四):THULAC
THULAC是一款相當不錯的中文分詞工具,準確率高、分詞速度蠻快的;並且在工程上做了很多優化,比如:用DAT儲存訓練特徵(壓縮訓練模型),加入了標點符號的特徵(提高分詞準確率)等。 【開源中文分詞工具探析】系列: 1. 前言 THULAC所採用的分詞模型為結構化感知器(Structured Percep
開源中文分詞工具探析(五):FNLP
FNLP是由Fudan NLP實驗室的邱錫鵬老師開源的一套Java寫就的中文NLP工具包,提供諸如分詞、詞性標註、文字分類、依存句法分析等功能。 【開源中文分詞工具探析】系列: 1. 前言 類似於THULAC,FNLP也是採用線性模型(linear model)分詞。較於對數線性模型(log-linea
中文分詞工具探析(一):ICTCLAS (NLPIR)
【開源中文分詞工具探析】系列: 1. 前言 ICTCLAS是張華平老師推出的中文分詞系統,於2009年更名為NLPIR。ICTCLAS是中文分詞界元老級工具了,作者開放出了free版本的原始碼(1.0整理版本在此). 作者在論文[1] 中宣稱ICTCLAS是基於HHMM(Hierarchical Hid
中文分詞工具探析(二):Jieba
【開源中文分詞工具探析】系列: 1. 前言 Jieba是由fxsjy大神開源的一款中文分詞工具,一款屬於工業界的分詞工具——模型易用簡單、程式碼清晰可讀,推薦有志學習NLP或Python的讀一下原始碼。與採用分詞模型Bigram + HMM 的ICTCLAS 相類似,Jieba採用的是Unigram +
數列分塊入門九題(三):LOJ6283~6285
freopen ans cstring 離散化 fin 利用 ace reg 有序 Preface 最後一題我一直覺得用莫隊是最好的。 數列分塊入門 7——區間乘法,區間加法,單點詢問 還是很簡單的吧,比起數列分塊入門 7就多了個區間乘。 類似於線段樹,由於乘法的優先級高
北大開源全新中文分詞工具包:準確率遠超THULAC、結巴分詞
選自GitHub,作者:羅睿軒、許晶晶、孫栩,機器之心編輯。 最近,北大開源了一箇中文分詞工具包,它在多個分詞資料集上都有非常高的分詞準確率。其中廣泛使用的結巴分詞誤差率高達 18.55% 和 20.42,而北大的 pkuseg 只有 3.25% 與 4.32%。 pkuseg 是由北京
在PyCharm(Python整合開發環境)中安裝jieba中文分詞工具包
PyCharm IDE中,可以直接引入各種工具包。jieba中文分詞工具包安裝非常方便。 1、開啟Pycharm,點選左上角 >>File >>Settings。 2、在settings介面中點選Project :***(專案名稱) >
PyNLPIR python中文分詞工具
命名 hub 兩個 工具 ict mage ret wid tty 官網:https://pynlpir.readthedocs.io/en/latest/ github:https://github.com/tsroten/pynlpir NLPIR分詞系
7個優秀的開源中文分詞庫推薦
中文分詞是中文文字處理的基礎步驟,也是中文人機自然語言互動的基礎模組。由於中文句子中沒有詞的界限,因此在進行中文自然語言處理時,通常需要先進行分詞。 縱觀整個開源領域,陸陸續續做中文分詞的也有不少,不過目前仍在維護的且質量較高的並不多。下面整理了一些個人認為比較優秀的中文分詞庫,以供大家
Hanlp等七種優秀的開源中文分詞庫推薦
中文分詞是中文文字處理的基礎步驟,也是中文人機自然語言互動的基礎模組。由於中文句子中沒有詞的界限,因此在進行中文自然語言處理時,通常需要先進行分詞。 縱觀整個開源領域,陸陸續續做中文分詞的也有不少,不過目前仍在維護的且質量較高的並不多。下面整理了一些個人認為比較優秀的中文分
10大Java開源中文分詞器的使用方法和分詞效果對比
原文地址:http://my.oschina.net/apdplat/blog/412921 本文的目標有兩個: 1、學會使用10大Java開源中文分詞器 2、對比分析10 大Java開源中文分詞器的分詞效果 本文給出了10大Java開源中文分詞的使用方法以及分詞
【NLP】11大Java開源中文分詞器的使用方法和分詞效果對比
本文的目標有兩個: 1、學會使用11大Java開源中文分詞器 2、對比分析11大Java開源中文分詞器的分詞效果 本文給出了11大Java開源中文分詞的使用方法以及分詞結果對比程式碼,至於效果哪個好,那要用的人結合自己的應用場景自己來判斷。 11大Java開源中文分詞器,不同的分詞器
Solr與開源中文分詞(ansj)整合
1. ansj分詞原始碼及jar包下載地址 原始碼: https://github.com/NLPchina/ansj_seg jar包: http://maven.nlpcn.org/org/ansj/ http://maven.nlpcn.org/org/nlpcn/n
中文分詞工具thulac4j釋出
1. 介紹 thulac4j是THULAC的Java 8工程化實現,具有分詞速度快、準、強的特點;支援 自定義詞典 繁體轉簡體 停用詞過濾 若想在專案中使用thulac4j,可新增依賴: <dependency> <groupId>io.github.yizhiru</g
乾貨 | 史上最全中文分詞工具整理
作者 | fendouai 一.中文分詞 分詞服務介面列表 二.準確率評測: THULAC:與代表性分詞軟體的效能對比 我們選擇LTP-3.2.0 、ICTCLAS(2015版) 、jieba(C++版)等國內具代表性的分詞軟體與THULAC做效能
中文分詞工具
THULAC 四款python中中文分詞的嘗試。嘗試的有:jieba、SnowNLP(MIT)、pynlpir(大資料搜尋挖掘實驗室(北京市海量語言資訊處理與雲端計算應用工程技術研究中心))、thulac(清華大學自然語言處理與社會人文計算實驗室) 四款都
python中文分詞工具:結巴分詞jieba
結巴分詞jieba特點 支援三種分詞模式: 精確模式,試圖將句子最精確地切開,適合文字分析; 全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義; 搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提