CRF++中文分词使用指南

http://blog.csdn.net/marising/article/details/5769653

前段时间写了中文分词的一些记录里面提到了CRF的分词方法,近段时间又研究了一下,特把方法写下来,以备忘,另外,李沫南同学优化过CRF++,见:http://www.coreseek.cn/opensource/CRF/。我觉得CRF++还有更大的优化空间,以后有时间再搞。

1 下载和安装

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

我用的是Ubutnu,所以,下载的是源码:http://sourceforge.net/projects/crfpp/files/ 下载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文件

[python] view plaincopy

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import sys
  4. #home_dir = "D:/source/NLP/people_daily//"
  5. home_dir = "/home/lhb/workspace/CRF_data/"
  6. def splitWord(words):
  7. uni = words.decode(‘utf-8‘)
  8. li = list()
  9. for u in uni:
  10. li.append(u.encode(‘utf-8‘))
  11. return li
  12. #4 tag
  13. #S/B/E/M
  14. def get4Tag(li):
  15. length = len(li)
  16. #print length
  17. if length   == 1:
  18. return [‘S‘]
  19. elif length == 2:
  20. return [‘B‘,‘E‘]
  21. elif length > 2:
  22. li = list()
  23. li.append(‘B‘)
  24. for i in range(0,length-2):
  25. li.append(‘M‘)
  26. li.append(‘E‘)
  27. return li
  28. #6 tag
  29. #S/B/E/M/M1/M2
  30. def get6Tag(li):
  31. length = len(li)
  32. #print length
  33. if length   == 1:
  34. return [‘S‘]
  35. elif length == 2:
  36. return [‘B‘,‘E‘]
  37. elif length == 3:
  38. return [‘B‘,‘M‘,‘E‘]
  39. elif length == 4:
  40. return [‘B‘,‘M1‘,‘M‘,‘E‘]
  41. elif length == 5:
  42. return [‘B‘,‘M1‘,‘M2‘,‘M‘,‘E‘]
  43. elif length > 5:
  44. li = list()
  45. li.append(‘B‘)
  46. li.append(‘M1‘)
  47. li.append(‘M2‘)
  48. for i in range(0,length-4):
  49. li.append(‘M‘)
  50. li.append(‘E‘)
  51. return li
  52. def saveDataFile(trainobj,testobj,isTest,word,handle,tag):
  53. if isTest:
  54. saveTrainFile(testobj,word,handle,tag)
  55. else:
  56. saveTrainFile(trainobj,word,handle,tag)
  57. def saveTrainFile(fiobj,word,handle,tag):
  58. if len(word) > 0:
  59. wordli = splitWord(word)
  60. if tag == ‘4‘:
  61. tagli = get4Tag(wordli)
  62. if tag == ‘6‘:
  63. tagli = get6Tag(wordli)
  64. for i in range(0,len(wordli)):
  65. w = wordli[i]
  66. h = handle
  67. t = tagli[i]
  68. fiobj.write(w + ‘/t‘ + h + ‘/t‘ + t + ‘/n‘)
  69. else:
  70. #print ‘New line‘
  71. fiobj.write(‘/n‘)
  72. #B,M,M1,M2,M3,E,S
  73. def convertTag(tag):
  74. fiobj    = open( home_dir + ‘people-daily.txt‘,‘r‘)
  75. trainobj = open( home_dir + tag + ‘.train.data‘,‘w‘ )
  76. testobj  = open( home_dir + tag + ‘.test.data‘,‘w‘)
  77. arr = fiobj.readlines()
  78. i = 0
  79. for a in arr:
  80. i += 1
  81. a = a.strip(‘/r/n/t ‘)
  82. words = a.split(‘ ‘)
  83. test = False
  84. if i % 10 == 0:
  85. test = True
  86. for word in words:
  87. word = word.strip(‘/t ‘)
  88. if len(word) > 0:
  89. i1 = word.find(‘[‘)
  90. if i1 >= 0:
  91. word = word[i1+1:]
  92. i2 = word.find(‘]‘)
  93. if i2 > 0:
  94. word = word[:i2]
  95. word_hand = word.split(‘/‘)
  96. w,h = word_hand
  97. #print w,h
  98. if h == ‘nr‘:    #ren min
  99. #print ‘NR‘,w
  100. if w.find(‘·‘) >= 0:
  101. tmpArr = w.split(‘·‘)
  102. for tmp in tmpArr:
  103. saveDataFile(trainobj,testobj,test,tmp,h,tag)
  104. continue
  105. if h != ‘m‘:
  106. saveDataFile(trainobj,testobj,test,w,h,tag)
  107. if h == ‘w‘:
  108. saveDataFile(trainobj,testobj,test,"","",tag) #split
  109. trainobj.flush()
  110. testobj.flush()
  111. if __name__ == ‘__main__‘:
  112. if len(sys.argv) < 2:
  113. print ‘tag[6,4] convert raw data to train.data and tag.test.data‘
  114. else:
  115. tag = sys.argv[1]
  116. convertTag(tag)

下载下来并解压,然后用脚本整理数据,注意home_dir改为语料的目录:
python ./peopledata.py 6

90%数据作为训练数据,10%的数据作为测试数据,生成的文件如:
6.test.data
6.train.data

模板文件的写法如下
template:

[python] view plaincopy

  1. # Unigram
  2. U00:%x[-1,0]
  3. U01:%x[0,0]
  4. U02:%x[1,0]
  5. U03:%x[-1,0]/%x[0,0]
  6. U04:%x[0,0]/%x[1,0]
  7. U05:%x[-1,0]/%x[1,0]
  8. # Bigram
  9. B

%x[row,column]代表的是行和列,[-1,0]表示前1个字的第1列,[0,0]当前字的第1列,[1,0]后1个字的第1列

4 执行和结果查看 
6exec.sh文件

[python] view plaincopy

  1. #!/bin/sh
  2. ./crf_learn -f 3 -c 4.0 template 6.train.data 6.model > 6.train.rst
  3. ./crf_test -m 6.model 6.test.data > 6.test.rst
  4. ./crfeval.py 6.test.rst
  5. #./crf_learn -a MIRA -f 3 template train.data model
  6. #./crf_test -m model test.data
  7. #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文件为

[python] view plaincopy

  1. #!/bin/sh
  2. ./crf_learn -f 3 -c 4.0 template 4.train.data 4.model > 4.train.rst
  3. ./crf_test -m 4.model 4.test.data > 4.test.rst
  4. ./crfeval.py 4.test.rst

4Tag的效果为
[email protected]calhost:~/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要好,可以尝试以下。

[python] view plaincopy

  1. # Unigram
  2. U00:%x[-1,1]
  3. U01:%x[0,1]
  4. U02:%x[1,1]
  5. U03:%x[-1,1]/%x[0,1]
  6. U04:%x[0,1]/%x[1,1]
  7. U05:%x[-1,1]/%x[1,1]
  8. U06:%x[-1,0]
  9. U07:%x[0,0]
  10. U08:%x[1,0]
  11. U09:%x[-1,0]/%x[0,0]
  12. U010:%x[0,0]/%x[1,0]
  13. U011:%x[-1,0]/%x[1,0]
  14. # Bigram
  15. B

有某位同学问我要crfeval.py文件,特放出如下:

[python] view plaincopy

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import sys
  4. if __name__=="__main__":
  5. try:
  6. file = open(sys.argv[1], "r")
  7. except:
  8. print "result file is not specified, or open failed!"
  9. sys.exit()
  10. wc_of_test = 0
  11. wc_of_gold = 0
  12. wc_of_correct = 0
  13. flag = True
  14. for l in file:
  15. if l==‘/n‘: continue
  16. _, _, g, r = l.strip().split()
  17. if r != g:
  18. flag = False
  19. if r in (‘E‘, ‘S‘):
  20. wc_of_test += 1
  21. if flag:
  22. wc_of_correct +=1
  23. flag = True
  24. if g in (‘E‘, ‘S‘):
  25. wc_of_gold += 1
  26. print "WordCount from test result:", wc_of_test
  27. print "WordCount from golden data:", wc_of_gold
  28. print "WordCount of correct segs :", wc_of_correct
  29. #查全率
  30. P = wc_of_correct/float(wc_of_test)
  31. #查准率,召回率
  32. R = wc_of_correct/float(wc_of_gold)
  33. print "P = %f, R = %f, F-score = %f" % (P, R, (2*P*R)/(P+R))
时间: 2024-11-07 11:42:32

CRF++中文分词使用指南的相关文章

求同存异,共创双赢 - 基于对抗网络的利用不同分词标准语料的中文分词方法 | 论文访谈间 #06

https://mp.weixin.qq.com/s/P-a-n1PsBL5hLZWVxyuLQw 「论文访谈间」是由 PaperWeekly 和中国中文信息学会青工委联合发起的论文报道栏目,旨在让国内优质论文得到更多关注和认可. 这是第 6 期「论文访谈间」 论文作者 | 陈新驰.施展.邱锡鹏.黄萱菁(复旦大学) 特约记者 | 郑华滨(中山大学) 在中文信息处理中,分词(word segmentation)是一项基本技术,因为中文的词汇是紧挨着的,不像英文有一个天然的空格符可以分隔开不同的单词

基于CRF的中文分词

http://biancheng.dnbcw.info/java/341268.html CRF简介 Conditional Random Field:条件随机场,一种机器学习技术(模型) CRF由John Lafferty最早用于NLP技术领域,其在NLP技术领域中主要用于文本标注,并有多种应用场景,例如: 分词(标注字的词位信息,由字构词) 词性标注(标注分词的词性,例如:名词,动词,助词) 命名实体识别(识别人名,地名,机构名,商品名等具有一定内在规律的实体名词) 本文主要描述如何使用CR

97.5%准确率的深度学习中文分词(字嵌入+Bi-LSTM+CRF)

http://www.17bigdata.com/97-5%E5%87%86%E7%A1%AE%E7%8E%87%E7%9A%84%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E4%B8%AD%E6%96%87%E5%88%86%E8%AF%8D%EF%BC%88%E5%AD%97%E5%B5%8C%E5%85%A5bi-lstmcrf%EF%BC%89.html 摘要 深度学习当前在NLP领域发展也相当快,翻译,问答,摘要等基本都被深度学习占领了. 本文给出基于深度

中文分词入门之字标注法4

http://www.52nlp.cn/%E4%B8%AD%E6%96%87%E5%88%86%E8%AF%8D%E5%85%A5%E9%97%A8%E4%B9%8B%E5%AD%97%E6%A0%87%E6%B3%A8%E6%B3%954 上一节主要介绍的是利用最大熵工具包来做字标注中文分词,这一节我们直奔主题,借用条件随机场工具“CRF++: Yet Another CRF toolkit”来完成字标注中文分词的全过程. 关于条件随机场(CRF)的背景知识,推荐参考阅读一些经典的文献:<条件

中文分词

一周乱谈(第八周) - 中文分词 中文分词 NLP(Natural language processing)自然语言处理一直都是比较热门的领域,现在不管是搜索,推荐神马的基本都需要和nlp打交道,而中文的nlp处理的第一步就是分词了,所以中文分词一直扮演者举足轻重的角色.当然了,分词的算法也是层出不穷,从最初的字典匹配到后来的统计模型,从HMM到CRF,分词精度都在不断提高,下面我就简单介绍下基本的分词算法. 字典匹配 最简单的分词就是基于字典匹配,一个句子“乱谈中文分词”,如果字典中我有这三个

隐含马尔可夫模型HMM的中文分词器 入门-1

<pre name="code" class="sql">http://sighan.cs.uchicago.edu/bakeoff2005/ http://www.52nlp.cn/中文分词入门之资源 中文分词入门之资源 作为中文信息处理的"桥头堡",中文分词在国内的关注度似乎远远超过了自然语言处理的其他研究领域.在中文分词中,资源的重要性又不言而喻,最大匹配法等需要一个好的词表,而基于字标注的中文分词方法又需要人工加工好的分词语料

一周乱谈(第八周) - 中文分词

中文分词 NLP(Natural language processing)自然语言处理一直都是比较热门的领域,现在不管是搜索,推荐神马的基本都需要和nlp打交道,而中文的nlp处理的第一步就是分词了,所以中文分词一直扮演者举足轻重的角色.当然了,分词的算法也是层出不穷,从最初的字典匹配到后来的统计模型,从HMM到CRF,分词精度都在不断提高,下面我就简单介绍下基本的分词算法. 字典匹配 最简单的分词就是基于字典匹配,一个句子“乱谈中文分词”,如果字典中我有这三个词“乱谈”“中文”“分词”那么我自

【中文分词】结构化感知器SP

结构化感知器(Structured Perceptron, SP)是由Collins [1]在EMNLP'02上提出来的,用于解决序列标注的问题.中文分词工具THULAC.LTP所采用的分词模型便是基于此. 1. 结构化感知器 模型 CRF全局化地以最大熵准则建模概率P(Y|X)P(Y|X):其中,XX为输入序列xn1x1n,YY为标注序列yn1y1n.不同于CRF,SP则是(同样以最大熵准则)建模score函数: S(Y,X)=∑sαsΦs(Y,X)S(Y,X)=∑sαsΦs(Y,X) 其中,

NLP︱中文分词技术小结、几大分词引擎的介绍与比较

笔者想说:觉得英文与中文分词有很大的区别,毕竟中文的表达方式跟英语有很大区别,而且语言组合形式丰富,如果把国外的内容强行搬过来用,不一样是最好的.所以这边看到有几家大牛都在中文分词以及NLP上越走越远.哈工大以及北大的张华平教授(NLPIR)的研究成果非常棒! 但是商业应用的过程中存在的以下的问题: 1.是否先利用开源的分词平台进行分词后,再自己写一些算法进行未登录词.歧义词的识别? 2.或者直接调用下文介绍的分词引擎来进行分词呢?缴费使用固然很棒,但是是否值得? ---------------