CRF++中文分詞使用指南

來源:互聯網
上載者:User

前段時間寫了中文分詞的一些記錄裡面提到了CRF的分詞方法,近段時間又研究了一下,特把方法寫下來,以備忘,另外,李沫南同學最佳化過CRF++,見:http://www.coreseek.cn/opensource/CRF/。我覺得CRF++還有更大的最佳化空間,以後有時間再搞。

 

1 下載和安裝

CRF的概念,請google,我就不浪費資源啦。官方地址如下:http://crfpp.sourceforge.net/

我用的是Ubutnu,所以,下載的是源碼:http://sourceforge.net/projects/crfpp/files/ 下載

ext_gz

dload filename { url: 'http://downloads.sourceforge.net/project/crfpp/crfpp/0.54/CRF%2B%2B-0.54.tar.gz?ts=1280225110' }" title="/crfpp/0.54/CRF++-0.54.tar.gz: released on 2010-05-15" href="http://sourceforge.net/projects/crfpp/files/crfpp/0.54/CRF%2B%2B-0.54.tar.gz/download">CRF++-0.54.tar.gz

沒有gcc/g++/make請安裝
% ./configure
% make
% sudo make install

2 測試和體驗
在源碼包中有example,可以執行./exec.sh體驗一下
exec.sh   #訓練和測試指令碼
template #模板檔案
test.data #測試檔案
train.data #訓練檔案
可以開啟看看

3 語料整理和模板編寫

我採用的是6Tag和6Template的方式
S,單個詞;B,詞首;E,詞尾;M1/M2/M,詞中

1個字的詞:
和 S
2個字的詞(注意是實際上是一個字一行,我為了排版,改為橫排的了):
中 B 國 E
3個字的詞:
進 B 一 M 步 E
5個字的詞:
發 B 展 M1 中 M2 國 M 家 E
跟多字的詞
中 B 華 M1 人 M2 民 M 共 M 和 M國 E
標點符號作為單詞(S表示)

從bamboo 項目中下載:people-daily.txt.gz
pepoledata.py檔案
#!/usr/bin/python</p><p># -*- coding: utf-8 -*-</p><p>import sys</p><p>#home_dir = "D:/source/NLP/people_daily//"</p><p>home_dir = "/home/lhb/workspace/CRF_data/"<br />def splitWord(words):<br /> uni = words.decode('utf-8')<br /> li = list()<br /> for u in uni:<br />li.append(u.encode('utf-8'))<br /> return li</p><p>#4 tag</p><p>#S/B/E/M<br />def get4Tag(li):<br /> length = len(li)<br /> #print length<br /> if length == 1:<br />return ['S']<br /> elif length == 2:<br />return ['B','E']<br /> elif length > 2:<br />li = list()<br />li.append('B')<br />for i in range(0,length-2):<br /> li.append('M')<br />li.append('E')<br />return li<br />#6 tag<br />#S/B/E/M/M1/M2<br />def get6Tag(li):<br /> length = len(li)<br /> #print length<br /> if length == 1:<br />return ['S']<br /> elif length == 2:<br />return ['B','E']<br /> elif length == 3:<br />return ['B','M','E']<br /> elif length == 4:<br />return ['B','M1','M','E']<br /> elif length == 5:<br />return ['B','M1','M2','M','E']<br /> elif length > 5:<br />li = list()<br />li.append('B')<br />li.append('M1')<br />li.append('M2')<br />for i in range(0,length-4):<br /> li.append('M')<br />li.append('E')<br />return li</p><p>def saveDataFile(trainobj,testobj,isTest,word,handle,tag):<br /> if isTest:<br />saveTrainFile(testobj,word,handle,tag)<br /> else:<br />saveTrainFile(trainobj,word,handle,tag)</p><p>def saveTrainFile(fiobj,word,handle,tag):<br /> if len(word) > 0:<br />wordli = splitWord(word)<br />if tag == '4':<br /> tagli = get4Tag(wordli)<br />if tag == '6':<br /> tagli = get6Tag(wordli)<br />for i in range(0,len(wordli)):<br /> w = wordli[i]<br /> h = handle<br /> t = tagli[i]<br /> fiobj.write(w + '/t' + h + '/t' + t + '/n')<br /> else:<br />#print 'New line'<br />fiobj.write('/n')</p><p>#B,M,M1,M2,M3,E,S<br />def convertTag(tag):<br /> fiobj = open( home_dir + 'people-daily.txt','r')<br /> trainobj = open( home_dir + tag + '.train.data','w' )<br /> testobj = open( home_dir + tag + '.test.data','w')</p><p> arr = fiobj.readlines()<br /> i = 0<br /> for a in arr:<br />i += 1<br />a = a.strip('/r/n/t ')<br />words = a.split(' ')<br />test = False<br />if i % 10 == 0:<br /> test = True<br />for word in words:<br /> word = word.strip('/t ')<br /> if len(word) > 0:<br />i1 = word.find('[')<br />if i1 >= 0:<br /> word = word[i1+1:]<br />i2 = word.find(']')<br />if i2 > 0:<br /> word = word[:i2]<br />word_hand = word.split('/')<br />w,h = word_hand<br />#print w,h<br />if h == 'nr': #ren min<br /> #print 'NR',w<br /> if w.find('·') >= 0:<br />tmpArr = w.split('·')<br />for tmp in tmpArr:<br /> saveDataFile(trainobj,testobj,test,tmp,h,tag)<br />continue<br />if h != 'm':<br /> saveDataFile(trainobj,testobj,test,w,h,tag)</p><p>if h == 'w':<br /> saveDataFile(trainobj,testobj,test,"","",tag) #split</p><p>trainobj.flush()<br />testobj.flush()</p><p>if __name__ == '__main__':<br /> if len(sys.argv) < 2:<br />print 'tag[6,4] convert raw data to train.data and tag.test.data'<br /> else:<br />tag = sys.argv[1]<br />convertTag(tag)
下載下來並解壓,然後用指令碼整理資料,注意home_dir改為語料的目錄:
python ./peopledata.py 6

90%資料作為訓練資料,10%的資料作為測試資料,產生的檔案如:
6.test.data
6.train.data

模板檔案的寫法如下
template:
# Unigram<br />U00:%x[-1,0]<br />U01:%x[0,0]<br />U02:%x[1,0]<br />U03:%x[-1,0]/%x[0,0]<br />U04:%x[0,0]/%x[1,0]<br />U05:%x[-1,0]/%x[1,0]</p><p># Bigram<br />B

%x[row,column]代表的是行和列,[-1,0]表示前1個字的第1列,[0,0]當前字的第1列,[1,0]後1個字的第1列

4 執行和結果查看
6exec.sh檔案
#!/bin/sh<br />./crf_learn -f 3 -c 4.0 template 6.train.data 6.model > 6.train.rst<br />./crf_test -m 6.model 6.test.data > 6.test.rst<br />./crfeval.py 6.test.rst</p><p>#./crf_learn -a MIRA -f 3 template train.data model<br />#./crf_test -m model test.data<br />#rm -f model

WordCount from test result: 109805
WordCount from golden data: 109948
WordCount of correct segs : 106145
P = 0.966668, R = 0.965411, F-score = 0.966039

5 調整Tag和模板
4 Tag S/B/M/E 比 6Tag 去掉了M1和M2
python ./peopledata.py 4
4exec.sh檔案為
#!/bin/sh<br />./crf_learn -f 3 -c 4.0 template 4.train.data 4.model > 4.train.rst<br />./crf_test -m 4.model 4.test.data > 4.test.rst<br />./crfeval.py 4.test.rst
4Tag的效果為
lhb@localhost:~/workspace/CRF_data$ ./crfeval.py 4.test.rst
ordCount from test result: 109844
WordCount from golden data: 109948
WordCount of correct segs : 105985
P = 0.964868, R = 0.963956, F-score = 0.964412

6Tag的效果比4Tag有細微的差距,當然是6Tag好。

6Tag 訓練時間為
10062.00s
4tag的訓練時間為
4208.71s

6Tag的標註方法差異

1)把M放在E之前:
發 B 展 M1 中 M2 國 M 家 E
2)把M放在B後
發 B 展 M 中 M1 國 M2 家 E
3)把M放在M1和M2之間:
發 B 展 M1 中 M 國 M2 家 E
第1種方式效果最好,有細微的差距。
template的編寫

我嘗試過12行模板的編寫,把詞性作為一個計算因素,但是速度實在是很慢,沒跑完,我就關機了。效果應該比6 template要好,可以嘗試以下。

# Unigram<br />U00:%x[-1,1]<br />U01:%x[0,1]<br />U02:%x[1,1]<br />U03:%x[-1,1]/%x[0,1]<br />U04:%x[0,1]/%x[1,1]<br />U05:%x[-1,1]/%x[1,1]<br />U06:%x[-1,0]<br />U07:%x[0,0]<br />U08:%x[1,0]<br />U09:%x[-1,0]/%x[0,0]<br />U010:%x[0,0]/%x[1,0]<br />U011:%x[-1,0]/%x[1,0]</p><p># Bigram<br />B<br />

 

有某位同學問我要crfeval.py檔案,特放出如下:

 

#!/usr/bin/python<br /># -*- coding: utf-8 -*-</p><p>import sys</p><p>if __name__=="__main__":<br /> try:<br /> file = open(sys.argv[1], "r")<br /> except:<br /> print "result file is not specified, or open failed!"<br /> sys.exit()</p><p> wc_of_test = 0<br /> wc_of_gold = 0<br /> wc_of_correct = 0<br /> flag = True</p><p> for l in file:<br /> if l=='/n': continue</p><p> _, _, g, r = l.strip().split()</p><p> if r != g:<br /> flag = False</p><p> if r in ('E', 'S'):<br /> wc_of_test += 1<br /> if flag:<br /> wc_of_correct +=1<br /> flag = True</p><p> if g in ('E', 'S'):<br /> wc_of_gold += 1</p><p> print "WordCount from test result:", wc_of_test<br /> print "WordCount from golden data:", wc_of_gold<br /> print "WordCount of correct segs :", wc_of_correct</p><p> #查全率<br /> P = wc_of_correct/float(wc_of_test)<br /> #查准率,召回率<br /> R = wc_of_correct/float(wc_of_gold)</p><p> print "P = %f, R = %f, F-score = %f" % (P, R, (2*P*R)/(P+R))<br />

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.