工具包:https://taku910.github.io/crfpp/#tips

语料http://sighan.cs.uchicago.edu/bakeoff2005/

安装:

1)下载linux版本CRF++包-----CRF++-0.58.tar.gz,并解压。

2)cd CRF++-0.58

3)./configure

4)sudo make

5)sudo make install

若出现ImportError: libcrfpp.so.0: cannot open shared object file: No such file or directory 。
解决方法: ln -s /usr/local/lib/libcrfpp.so.0 /usr/lib/

第一步:准备训练语料

将backoff2005里的训练数据转化为CRF++所需的训练数据格式,采用4-tag( B(Begin,词首), E(End,词尾), M(Middle,词中), S(Single,单字词))标记集,处理utf-8编码文本。 原始训练集/icwb2-data/training/msr_training.utf8的形式是人工分好词的中文句子形式。如下:

“ 人们 常 说 生活 是 一 部 教科书 , 而 血 与 火 的 战争 > 更 是 不可多得 的 教科书 , 她 确实 是 名副其实 的 ‘ 我 的 > 大学 ’ 。
“ 心 静 渐 知 春 似 海 , 花 深 每 觉 影 生 香 。
“ 吃 屎 的 东西 , 连 一 捆 麦 也 铡 不 动 呀 ?
他 “ 严格要求 自己 , 从 一个 科举 出身 的 进士 成为 一个 伟> 大 的 民主主义 者 , 进而 成为 一 位 杰出 的 党外 共产主义 战 士 , 献身 于 崇高 的 共产主义 事业 。
“ 征 而 未 用 的 耕地 和 有 收益 的 土地 , 不准 荒芜 。
“ 这 首先 是 个 民族 问题 , 民族 的 感情 问题 。
’ 我 扔 了 两颗 手榴弹 , 他 一下子 出 溜 下去 。
“ 废除 先前 存在 的 所有制 关系 , 并不是 共产主义 所 独具 的 特征 。
“ 这个 案子 从 始 至今 我们 都 没有 跟 法官 接触 过 , 也 > 没有 跟 原告 、 被告 接触 过 。
“ 你 只有 把 事情 做好 , 大伙 才 服 你

根据如下的脚本 make_crf_train.py,将这个训练语料转换为CRF++训练用的语料格式(2列,4-tag):

import codecs
import sys def character_tagging(input_file, output_file):
input_data = codecs.open(input_file, 'r', 'utf-8')
output_data = codecs.open(output_file, 'w', 'utf-8')
for line in input_data.readlines():
word_list = line.strip().split()
for word in word_list:
if len(word) == 1:
output_data.write(word + "\tS\n")
else:
output_data.write(word[0] + "\tB\n")
for w in word[1:len(word)-1]:
output_data.write(w + "\tM\n")
output_data.write(word[len(word)-1] + "\tE\n")
output_data.write("\n")
input_data.close()
output_data.close()

转化后如下:

“ S
人 B
们 E
常 S
说 S
生 B
活 E
是 S
一 S
部 S
教 B
科 M
书 E

第二步:训练模型

准备好训练语料,就可以利用crf的训练工具crf_learn来训练模型了,假设上述准备好的语料文件为:msr_training.tagging4crf.utf8

执行如下命令即可:
crf_learn -f 3 -c 4.0 ./template ./msr_training.tagging4crf.utf8 model   #执行此命令可以在安装文件外面新建一个文件夹进行,template是模板文件,model是训练完成后的model文件,只需要将模板,训练数据放到新建的文件夹里面,执行此命令就在当前文件夹下训练并生成了model文件

有四个主要的参数可以调整:
    -a CRF-L2 or CRF-L1     
    规范化算法选择。默认是CRF-L2。一般来说L2算法效果要比L1算法稍微好一点,虽然L1算法中非零特征的数值要比L2中大幅度的小。
    -c float
    这个参数设置CRF的hyper-parameter。c的数值越大,CRF拟合训练数据的程度越高。这个参数可以调整过度拟合和不拟合之间的平衡度。这个参数可以通过交叉验证等方法寻找较优的参数。
    -f NUM
    这个参数设置特征的cut-off threshold。CRF++使用训练数据中至少NUM次出现的特征。默认值为1。当使用CRF++到大规模数据时,只出现一次的特征可能会有几百万,这个选项就会在这样的情况下起到作用。
    -p NUM
    如果电脑有多个CPU,那么那么可以通过多线程提升训练速度。NUM是线程数量。

模板文件如下:

# Unigram
U00:%x[-2,0]
U01:%x[-1,0]
U02:%x[0,0]
U03:%x[1,0]
U04:%x[2,0]
U05:%x[-2,0]/%x[-1,0]/%x[0,0]
U06:%x[-1,0]/%x[0,0]/%x[1,0]
U07:%x[0,0]/%x[1,0]/%x[2,0]
U08:%x[-1,0]/%x[0,0]
U09:%x[0,0]/%x[1,0] # Bigram
B

第三步:准备测试语料并进行测试

有了模型,现在我们需要做得还是准备一份CRF++用的测试语料,然后利用CRF++的测试工具crf_test进行字标注。原始的测试语料是icwb2-data/testing/msr_test.utf8 ,样例如下:

扬帆远东做与中国合作的先行
希腊的经济结构较特殊。
海运业雄踞全球之首,按吨位计占世界总数的17%。
另外旅游、侨汇也是经济收入的重要组成部分,制造业规模相对较小。
多年来,中希贸易始终处于较低的水平,希腊几乎没有在中国投资。
十几年来,改革开放的中国经济高速发展,远东在崛起。
瓦西里斯的船只中有40%驶向远东,每个月几乎都有两三条船停靠中国港口。
他感受到了中国经济发展的大潮。
他要与中国人合作。
他来到中国,成为第一个访华的大船主。

这里我们同样提供一个python脚本 make_crf_test.py 对测试语料进行处理,将其转换为CRF++要求的格式(2列,B作为最后一列的占位符)

import codecs
import sys def character_split(input_file, output_file):
input_data = codecs.open(input_file, 'r', 'utf-8')
output_data = codecs.open(output_file, 'w', 'utf-8')
for line in input_data.readlines():
for word in line.strip():
word = word.strip()
if word:
output_data.write(word + "\tB\n")
input_data.close()
output_data.close()

转化后如下(注意中间不要有空行,否则标注结果全部为S):

扬 B
帆 B
远 B
东 B
做 B
与 B
中 B
国 B
 
假设上述测试语料为msr_test4crf.utf8,执行crf_test即可得到字标注结果:
crf_test -m ./crf_model  ./msr_test4crf.utf8 > msr_test4crf.tag.utf8
标注后样例如下:
扬 B B
帆 B E
远 B B
东 B E
做 B S
与 B S
中 B B
国 B E
合 B B
作 B E
 
第四步:将标注的词位信息转化为分词结果
import codecs
import sys
def character_2_word(input_file, output_file):
input_data = codecs.open(input_file, 'r', 'utf-8')
output_data = codecs.open(output_file, 'w', 'utf-8')
for line in input_data.readlines():
if line == "\n":
output_data.write("\n")
else:
char_tag_pair = line.strip().split('\t')
char = char_tag_pair[0]
tag = char_tag_pair[2]
if tag == 'B':
output_data.write(' ' + char)
elif tag == 'M':
output_data.write(char)
elif tag == 'E':
output_data.write(char + ' ')
else: # tag == 'S'
output_data.write(' ' + char + ' ')
input_data.close()
output_data.close()

转化后如下:

扬帆 远东 做 与 中国 合作 的 先行
希腊 的 经济 结构 较 特殊 。
海运 业 雄踞 全球 之 首 , 按 吨 位 计 占 世界 总数 的 17% 。
另外 旅游 、 侨汇 也是 经济 收入 的 重要 组成部分 , 制造业 规模 相对 较小 。
多年来 , 中 希 贸易 始终 处于 较低 的 水平 , 希腊 几乎 没有 在 中国 投资 。
十几年 来 , 改革开放 的 中国 经济 高速 发展 , 远东 在 崛起 。
瓦西里斯 的 船只 中 有 40% 驶 向 远东 , 每个 月 几乎 都 有 两三条 船 停靠 中国 港口 。
他 感受 到 了 中国 经济 发展 的 大潮 。
他 要 与 中国人 合作 。
他 来到 中国 , 成为 第一个 访 华 的 大船 主

最后:评估一下分词效果

有了这个CRF字标注分词结果,我们就可以利用backoff2005的测试脚本来测一下这次分词的效果了:
./icwb2-data/scripts/score ./icwb2-data/gold/msr_training_words.utf8 ./icwb2-data/gold/msr_test_gold.utf8 msr_test4crf.tag2word.utf8 > msr_crf_segment.score
结果如下:
=== SUMMARY:
=== TOTAL INSERTIONS: 1412
=== TOTAL DELETIONS: 1305
=== TOTAL SUBSTITUTIONS: 2449
=== TOTAL NCHANGE: 5166
=== TOTAL TRUE WORD COUNT: 106873
=== TOTAL TEST WORD COUNT: 106980
=== TOTAL TRUE WORDS RECALL: 0.965
=== TOTAL TEST WORDS PRECISION: 0.964
=== F MEASURE: 0.964
=== OOV Rate: 0.026
=== OOV Recall Rate: 0.647
=== IV Recall Rate: 0.974
### msr_test4crf.tag2word.utf8 1412 1305 2449 5166 106873 106980 0.965 0.964 0.964 0.026 0.647 0.974
这次我们获得了一个准确率,召回率以及F值都在96%以上的结果,相对于前面几节的测试结果,这个CRF字标注分词结果还相对不错。

上面测试阶段略微繁琐一些,下面程序直接输入测试语料然后直接输出分词结果:

import codecs
import sys import CRFPP def crf_segmenter(input_file, output_file, tagger):
input_data = codecs.open(input_file, 'r', 'utf-8')
output_data = codecs.open(output_file, 'w', 'utf-8')
for line in input_data.readlines():
tagger.clear()
for word in line.strip():
word = word.strip()
if word:
tagger.add((word + "\to\tB").encode('utf-8'))
tagger.parse()
size = tagger.size()
xsize = tagger.xsize()
for i in range(0, size):
for j in range(0, xsize):
char = tagger.x(i, j).decode('utf-8')
tag = tagger.y2(i)
if tag == 'B':
output_data.write(' ' + char)
elif tag == 'M':
output_data.write(char)
elif tag == 'E':
output_data.write(char + ' ')
else:
output_data.write(' ' + char + ' ')
output_data.write('\n')
input_data.close()
output_data.close() if __name__ == '__main__':
if len(sys.argv) != 4:
print "Usage: python " + sys.argv[0] + " model input output"
sys.exit(-1)
crf_model = sys.argv[1]
input_file = sys.argv[2]
output_file = sys.argv[3]
tagger = CRFPP.Tagger("-m " + crf_model)
crf_segmenter(input_file, output_file, tagger)

只需执行“python crf_segmenter.py crf_model  ./icwb2-data/testing/msr_test.utf8  msr_test.seg.utf8”即可得到与前面几步得到的分词结果完全一致的CRF分词结果:msr_test.seg.utf8 。

参考连接:http://www.52nlp.cn/中文分词入门之字标注法4#comments

模板格式说明参考http://www.hankcs.com/nlp/the-crf-model-format-description.html

最新文章

  1. SAP CRM 复用视图
  2. JAVA并发编程J.U.C学习总结
  3. hadoop从非HA转到NAMENODE HA时需要注意的一个问题
  4. vs快捷方式
  5. TCP与UDP协议
  6. perl unload utf-8 oracle 数据库
  7. PHP字符串三种定义方式
  8. 我从.net转到java的心得和体会
  9. eclipse和sublime3打开freemarker(.ftl)文件
  10. SSH整合Maven教程
  11. IO 、NIO、AIO
  12. GIF录制
  13. C# 函数式编程及Monads.net库
  14. [转]IC行业的牛人
  15. Python3基础 list reversed 列表逆转并输出
  16. 经典算法 KMP算法详解
  17. BZOJ3329 Xorequ(数位dp+矩阵快速幂)
  18. Java EE之Servlet
  19. 【bzoj 2716】[Violet 3]天使玩偶 (CDQ+树状数组)
  20. unity代码设置鼠标样式

热门文章

  1. HDU 3579——Hello Kiki
  2. Android四大组件之Service(续2)
  3. BZOJ4919 大根堆(动态规划+treap+启发式合并)
  4. jsp - redirect重定向 / forward转发
  5. Linux内核分析5
  6. poj 1655 树的重心
  7. 【题解】Popping Balls AtCoder Code Festival 2017 qual B E 组合计数
  8. [吴恩达机器学习笔记]12支持向量机6SVM总结
  9. PowderDesign的使用
  10. Eclipse 使用mybatis generator插件自动生成代码