1. 程式人生 > >中文分詞工具探析(一):ICTCLAS (NLPIR)

中文分詞工具探析(一):ICTCLAS (NLPIR)

【開源中文分詞工具探析】系列:

1. 前言

ICTCLAS是張華平老師推出的中文分詞系統,於2009年更名為NLPIR。ICTCLAS是中文分詞界元老級工具了,作者開放出了free版本的原始碼(1.0整理版本在此). 作者在論文[1] 中宣稱ICTCLAS是基於HHMM(Hierarchical Hidden Markov Model)實現,後在論文[2]中改成了基於層疊隱馬爾可夫模型CHMM(Cascaded Hidden Markov Model)。我把HHMM的原論文[3]讀了一遍,對照ICTCLAS原始碼,發現ICTCLAS本質上就是一個Bigram的Word-Based Generative Model

,用HMM來做未登入詞識別(修正分詞)與詞性標註,與HHMM沒有半毛錢關係。Biagram語法模型對應於1階Markov假設,則ICTCLAS分詞模型的聯合概率為

\begin{equation}
P(w_1^m) = \prod_i P(w_{i} | w_{i-1})
\label{eq:bigram}
\end{equation}

2. ICTCLAS分解

ICTCLAS Free版的C++原始碼實在是佶屈聱牙,因本人水平有限,故參照的原始碼為sinboy的Java實現 ictclas4j"com.googlecode.ictclas4j" % "ictclas4j" % "1.0.1"

)。ICTCLAS分詞流程如下:

  1. 按照核心詞典進行第一次切詞;
  2. 在第一次切詞的基礎上,求解最大聯合概率\eqref{eq:bigram},作者稱之為“二元切分詞圖”;
  3. HMM識別未登入詞,諸如:人名、翻譯人名、地名、機構名等;
  4. 分詞結果整理,詞性標註。

詞典

ICTCLAS的詞典包括六種:

import org.ictclas4j.segment._

// 核心詞典
val coreDict = new Dictionary("data/coreDict.dct")
// 二元詞典
val bigramDict = new Dictionary("data/bigramDict.dct")
// 人名詞典
val personTagger = new PosTagger(Utility.TAG_TYPE.TT_PERSON, "data/nr", coreDict)
// 翻譯人名詞典
val transPersonTagger = new PosTagger(Utility.TAG_TYPE.TT_TRANS_PERSON, "data/tr", coreDict)
// 地名詞典
val placeTagger = new PosTagger(Utility.TAG_TYPE.TT_TRANS_PERSON, "data/ns", coreDict)
// 詞性標註
val lexTagger = new PosTagger(Utility.TAG_TYPE.TT_NORMAL, "data/lexical", coreDict)

其中,核心詞典(coreDict)用於初始切詞,二元詞典(bigramDict)記錄了兩個詞聯合出現的頻數。coreDict與bigramDict的資料格式如下

# coreDict
塊0 
  count:4 
    wordLen:0   frequency:3 handle:25856    word:(啊) 
    wordLen:0   frequency:69    handle:30976    word:(啊) 
    wordLen:2   frequency:0 handle:25856    word:(啊)呀 
    wordLen:2   frequency:0 handle:25856    word:(啊)喲 
塊1 
  count:133 
    wordLen:0   frequency:0 handle:26624    word:(阿) 
    wordLen:0   frequency:94    handle:27136    word:(阿) 
    ...
# bigramDict
塊0 
  count:9 
    wordLen:3   frequency:3 handle:3    word:(啊)@、 
    wordLen:3   frequency:4 handle:3    word:(啊)@。 
    wordLen:3   frequency:1 handle:3    word:(啊)@” 
    wordLen:3   frequency:39    handle:3    word:(啊)@! 
    wordLen:3   frequency:20    handle:3    word:(啊)@,

其中,frequency表示詞頻,handle表示詞性:

讓我們先看一個具體的例子:
wordLen:4 frequency:12 handle:28275 word:(愛)爾蘭
handle = 28275, 轉成HEX表示,為0x6E73。
把0x6E73解釋為字元陣列,0x6E -> 'n', 0x73 -> 's', 所以0x6E73 -> "ns"。
查北大的《漢語文字詞性標註標記集》, ns ~ 地名 (名詞程式碼n和處所詞程式碼s並在一起)。

計算

為了計算聯合概率\eqref{eq:bigram}最大值,ICTCLAS做了一個巧妙的轉換——求對數並做Linear interpolation平滑:

\[ \begin{aligned} \arg \max \prod_i P(w_{i} | w_{i-1}) & = \arg \min - \sum_i \log P(w_{i} | w_{i-1}) \\ & \approx \arg \min - \sum_i \log \left[ aP(w_{i-1}) + (1-a) P(w_{i}|w_{i-1}) \right] \end{aligned} \]

將所有的可能分詞組合構建成一個有向圖,邊的權重設為(上式中)平滑後的log值。由此,將求解最大聯合概率轉化成一個圖論中最短路徑問題。有時最大聯合概率對應的分詞結果不一定是最優的。為了解決這個問題,ICTCLAS採取了N-best策略,即求解N-最短路徑而不是直接求解最短路徑。然後在N-最短路徑的分詞結果上,做HMM修正——識別未登入詞與詞性標註。為了更清晰地瞭解分詞流程,我用scala把分詞函式SegTag::split()重新寫了一遍:

import java.util

import org.ictclas4j.bean.{Dictionary, SegNode}
import org.ictclas4j.segment._
import org.ictclas4j.utility.{POSTag, Utility}

import scala.collection.JavaConversions._

val sentence = "深夜的穆赫蘭道發生一樁車禍,女子麗塔在車禍中失憶了"
val pathCount = 1
// 儲存分詞結果
val stringBuilder = StringBuilder.newBuilder
// 按[空格|回車]分隔句子
val sentenceSeg = new SentenceSeg(sentence)
sentenceSeg.getSens.filter(_.isSeg).foreach { sen =>
  // 原子切分
  val as: AtomSeg = new AtomSeg(sen.getContent)
  // 全切分:根據核心詞典,生成所有的可能詞
  val segGraph: SegGraph = GraphGenerate.generate(as.getAtoms, coreDict)
  // 二元切分詞圖
  val biSegGraph: SegGraph = GraphGenerate.biGenerate(segGraph, coreDict, bigramDict)
  val nsp: NShortPath = new NShortPath(biSegGraph, pathCount)
  nsp.getPaths.foreach { onePath =>
    // 得到初次分詞路徑
    val segPath = getSegPath(segGraph, onePath)
    val firstPath = AdjustSeg.firstAdjust(segPath)
    // 處理未登陸詞,進對初次分詞結果進行優化
    val optSegGraph: SegGraph = new SegGraph(firstPath)
    personTagger.recognition(optSegGraph, firstPath)
    transPersonTagger.recognition(optSegGraph, firstPath)
    placeTagger.recognition(optSegGraph, firstPath)

    // 根據優化後的結果,重新進行生成二叉分詞圖表
    val optBiSegGraph: SegGraph = GraphGenerate.biGenerate(optSegGraph, coreDict, bigramDict)
    // 重新求取N-最短路徑
    val optNsp: NShortPath = new NShortPath(optBiSegGraph, pathCount)
    val optBipath: util.ArrayList[util.ArrayList[Integer]] = optNsp.getPaths

    // 詞性標記
    optBipath.foreach { optOnePath =>
      val optSegPath: util.ArrayList[SegNode] = getSegPath(optSegGraph, optOnePath)
      lexTagger.recognition(optSegPath)
      // 對分詞結果做最終的調整,主要是人名的拆分或重疊詞的合併
      val adjResult = AdjustSeg.finaAdjust(optSegPath, personTagger, placeTagger)
      val adjrs: String = outputResult(adjResult)
      stringBuilder ++= adjrs
    }
  }
}
println(stringBuilder.toString())
// 深夜/t 的/u 穆赫蘭/nr 道/q 發生/v 一/m 樁/q 車禍/n ,/w 女子/n 麗塔/nr 在/p 車禍/n 中/f 失/v 憶/vg 了/y

其中,呼叫了函式:

// 根據二叉分詞路徑生成分詞路徑
private def getSegPath(sg: SegGraph, biPath: util.ArrayList[Integer]): util.ArrayList[SegNode] = {
    sg != null && biPath != null match {
      case true =>
        val path = biPath.map { t => sg.getSnList.get(t) }
        new util.ArrayList[SegNode](path)
      case _ => null
    }
}

// 根據分詞路徑生成分詞結果
private def outputResult(wrList: util.ArrayList[SegNode]): String = {
    ...
}

後記:據聞ICTCLAS的第一版是作者在中科院讀碩期間完成的,雖說程式碼質量惹人吐槽,但是不得不驚歎於作者的程式碼功底以及在訓練模型上所下的功夫。

3. 參考資料

[1] Zhang, Hua-Ping, et al. "HHMM-based Chinese lexical analyzer ICTCLAS." Proceedings of the second SIGHAN workshop on Chinese language processing-Volume 17. Association for Computational Linguistics, 2003.
[2] 劉群, et al. "基於層疊隱馬模型的漢語詞法分析." 計算機研究與發展 41.8 (2004): 1421-1429.
[3] Fine, Shai, Yoram Singer, and Naftali Tishby. "The hierarchical hidden Markov model: Analysis and applications." Machine learning 32.1 (1998): 41-62.

相關推薦

中文工具ICTCLAS (NLPIR)

【開源中文分詞工具探析】系列: 1. 前言 ICTCLAS是張華平老師推出的中文分詞系統,於2009年更名為NLPIR。ICTCLAS是中文分詞界元老級工具了,作者開放出了free版本的原始碼(1.0整理版本在此). 作者在論文[1] 中宣稱ICTCLAS是基於HHMM(Hierarchical Hid

開源中文工具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

開源中文工具Ansj

Ansj是由孫健(ansjsun)開源的一箇中文分詞器,為ICTLAS的Java版本,也採用了Bigram + HMM分詞模型(可參考我之前寫的文章):在Bigram分詞的基礎上,識別未登入詞,以提高分詞準確度。雖然基本分詞原理與ICTLAS的一樣,但是Ansj做了一些工程上的優化,比如:用DAT高效地實現檢

中文工具Jieba

【開源中文分詞工具探析】系列: 1. 前言 Jieba是由fxsjy大神開源的一款中文分詞工具,一款屬於工業界的分詞工具——模型易用簡單、程式碼清晰可讀,推薦有志學習NLP或Python的讀一下原始碼。與採用分詞模型Bigram + HMM 的ICTCLAS 相類似,Jieba採用的是Unigram +

NLP詞法分析中文

##1.中文分詞介紹 中文分詞相較於英文分詞要難許多,因為英文字身就是由單詞與空格組成的,而中文則是由獨立的字組成的,但同時語義卻是有詞來表達的。因此對於中文的分析與研究,首先應尋找合適的方法進行分詞。現有的中文分詞技術主要分為規則分詞,統計分詞與規則加統計相結

在PyCharmPython整合開發環境中安裝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分詞系

Elasticsearch外掛ik

在Elasticsearch的對於中文的檢索,ik效果最好也是使用最火的一款中文分詞外掛。支援自定義詞庫和動態修改詞庫。對於一般情況的的中文檢索,ik分詞是一個很好的選擇。 安裝 版本號要跟Elasticsearch版本對應。 手動安裝: 1.在plugins

北大開源全新中文工具準確率遠超THULAC、結巴

選自GitHub,作者:羅睿軒、許晶晶、孫栩,機器之心編輯。 最近,北大開源了一箇中文分詞工具包,它在多個分詞資料集上都有非常高的分詞準確率。其中廣泛使用的結巴分詞誤差率高達 18.55% 和 20.42,而北大的 pkuseg 只有 3.25% 與 4.32%。 pkuseg 是由北京

中文工具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特點    支援三種分詞模式:        精確模式,試圖將句子最精確地切開,適合文字分析;        全模式,把句子中所有的可以成詞的詞語都掃描出來, 速度非常快,但是不能解決歧義;        搜尋引擎模式,在精確模式的基礎上,對長詞再次切分,提

jieba.NET是jieba中文的.NET版本C#實現

jieba.NET是jieba中文分詞的.NET版本(C#實現)。 當前版本為0.38.2,基於jieba 0.38,提供與jieba一致的功能與介面,以後可能會在jieba基礎上提供其它擴充套件功能。關於jieba的實現思路,可以看看這篇wiki裡提到的資料。 如果

Java中文工具AnsjSeg使用

        中文分詞是進行中文文字分析的一個重要步驟。對於Java語言,有許多可選的分詞工具,如中科院計算所的NLPIR(原ICTCLASS)、盤古分詞、IKAnalyzer、PaodingAnalyzer,其中,試用過ICTCLASS及其後續版本,剛開始感覺不錯,但是Java呼叫C語言的方式實在是受

布式利器Zookeeper

zookeeperZookeeper不論是在實際項目中,還是在各種分布式開源項目中都得到了廣泛應用,從本篇博客開始,將為大家帶來我對Zookeeper的認識。這個系列將會涵蓋Zookeeper的介紹、環境搭建、配置說明、Java操作Zookeeper(原生API方式)、zkclient操作Zookeeper方

[linux][MongoDB] mongodb學習MongoDB安裝、管理工具

ole ont mon mkdir man 管理工具 tar end 認證 參考原文:http://www.cnblogs.com/kaituorensheng/p/5118226.html linux安裝完美實現! 1. mongoDB安裝、啟動、關閉   1.1