CRF++ 中文分词
安装CRF和安装maxent差不多,都是./configure,make,sudo su,make install。CRF提供了各种语言的工具包,有java、python、perl等。我用的是python语言工具包,
所以还要安装python工具包:进入CRF++-0.58/python,python setup.py build ,(sudo) python setup.py install。安装完成后,可以打开python shell ,然后输入 import CRFPP,看看是否可以成功import,如果可以,就说明安装成功了。
CRF的example里有一个seg目录,里面是一个关于日文分词的例子。日文和中文很相似,所以用这个例子来训练model最合适了。
这里的训练集文件使用1998年1月份的《人民日报》语料 ,下载地址http://download.csdn.net/detail/u013378306/9740867
由于生成训练数据集后,有22M,测试的话,建议只用一部分。
中文语料部分:
- 19980101-01-001-001/m 迈向/v 充满/v 希望/n 的/u 新/a 世纪/n ——/w 一九九八年/t 新年/t 讲话/n (/w 附/v 图片/n 1/m 张/q )/w
- 19980101-01-001-002/m 中共中央/nt 总书记/n 、/w 国家/n 主席/n 江/nr 泽民/nr
- 19980101-01-001-003/m (/w 一九九七年/t 十二月/t 三十一日/t )/w
- 19980101-01-001-004/m 12月/t 31日/t ,/w 中共中央/nt 总书记/n 、/w 国家/n 主席/n 江/nr 泽民/nr 发表/v 1998年/t 新年/t 讲话/n 《/w 迈向/v 充满/v 希望/n 的/u 新/a 世纪/n 》/w 。/w (/w 新华社/nt 记者/n 兰/nr 红光/nr 摄/Vg )/w
为了得到适合拿来训练的数据集(4-tag标记),用到一个python脚本--make_crf_train_data.py:
- 词首,常用B表示
- 词中,常用M表示
- 词尾,常用E表示
- 单子词,常用S表示
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # make_crf_train_data.py
- # 得到CRF++要求的格式的训练文件
- # 用法:命令行--python make_crf_train_data.py input_file output_file
- # 4 tags for character tagging: B(Begin), E(End), M(Middle), S(Single)
- import codecs
- import sys
- def character_tagging(input_file, output_file):
- input_data = codecs.open(input_file, 'r', 'gbk')
- 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:
- words=word.split("/");
- if len(words)>=2:
- xz = words[1]
- word=words[0]
- if len(word) == 1:
- output_data.write(word + "\t"+xz+"\tS\n")
- else:
- output_data.write(word[0] + "\t"+xz+"\tB\n")
- for w in word[1:len(word) - 1]:
- output_data.write(w + "\t"+xz+"\tM\n")
- output_data.write(word[len(word) - 1] + "\t"+xz+"\tE\n")
- output_data.write("\n")
- input_data.close()
- output_data.close()
- '''''if __name__ == '__main__':
- if len(sys.argv) != 3:
- print "pls use: python make_crf_train_data.py input output"
- sys.exit()
- input_file = sys.argv[1]
- output_file = sys.argv[2]
- character_tagging(input_file, output_file)'''
- character_tagging("199801.txt", "train.data")
执行
- python make_crf_train_data.py inputFilePath tag4OutputFilePath
tag4OutputFilePath 部分:
- 1 m E
- 迈 v B
- 向 v E
- 充 v B
- 满 v E
- 希 n B
- 望 n E
- 的 u S
- 新 a S
- 世 n B
- 纪 n E
- — w B
- — w E
- 一 t B
- 九 t M
- 九 t M
- 八 t M
- 年 t E
- 新 t B
- 年 t E
- 讲 n B
- 话 n E
- ( w S
- 附 v S
- 图 n B
- 片 n E
- 1 m S
- 张 q S
- ) w S
有了训练语料,接下来就可以利用crf的训练工具crf_learn来训练模型了,切换到CRF++0.58目录下,执行如下命令即可:
- crf_learn -f 3 -c 1.5 ./example/seg/template ../tag4OutputFilePath crf_model
得到crf_model即为训练好的模型文件。
编写py文件分词 :crf_segmenter.py
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- #crf_segmenter.py
- #用法:命令行输入--python crf_segmenter.py crf_model input_file output_file
- # 利用CRF自带的python工具包,对输入文本进行分词
- 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: #tag == 'S'
- output_data.write(' ' + char + ' ')
- output_data.write('\n')
- input_data.close()
- output_data.close()
- if __name__ == '__main__':
- if len(sys.argv) != 4:
- print "pls use: python crf_segmenter.py model input output"
- sys.exit()
- 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 input_file output_file
- 中华人民工和国,中国国家主席江泽民,讲述了三个代表重要思想,我们要解放思想,实事求是,抓住机遇,实现祖国的和平统一,繁荣富强。
output_file:
- 中华 人民 工 和国 , 中国 国家 主席 江 泽民 ,讲 述了 三个 代表 重要 思想 ,我 们要 解放 思想 , 实事 求是 ,抓 住机 遇, 实现 祖国 的 和 平统 一, 繁荣 富强 。
从上面的结果可以看出,效果也不比之前的maxent理想,但这里主要是我的电脑在作孽,由于原来的训练数据太大了,大概有400多万行数据,我在电脑上跑了三次,结果三次都导致了系统崩溃,最后一次我从晚上十点开始跑数据,一直到第二天凌晨一点还没好,后来我就去睡觉了,电脑开着让它继续运行,结果第二天醒来,程序又崩溃了,所以后来我就截取了训练数据里的大概五万行数据用来训练model,结果就导致了正确率不高的问题,其实如果电脑给力的话,分词准确率大概有96%。这也是CRF的一个特点,它需要大量的数据来进行训练才能得到理想的效果。
最终分词效率:
- === SUMMARY:
- === TOTAL INSERTIONS: 99
- === TOTAL DELETIONS: 30
- === TOTAL SUBSTITUTIONS: 156
- === TOTAL NCHANGE: 285
- === TOTAL TRUE WORD COUNT: 821
- === TOTAL TEST WORD COUNT: 890
- === TOTAL TRUE WORDS RECALL: 0.773
- === TOTAL TEST WORDS PRECISION: 0.713
- === F MEASURE: 0.742
- === OOV Rate: 0.141
- === OOV Recall Rate: 0.259
- === IV Recall Rate: 0.858
- ### blog_test_segment.utf8 99 30 156 285 821 890 0.773 0.713 0.742 0.141 0.259 0.858
- <pre code_snippet_id="2137761" snippet_file_name="blog_20170118_1_4933737" name="code" class="html"><pre code_snippet_id="2137761" snippet_file_name="blog_20170118_1_4933737"></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <link rel="stylesheet" href="http://static.blog.csdn.net/public/res-min/markdown_views.css?v=2.0">
- </pre>
安装CRF和安装maxent差不多,都是./configure,make,sudo su,make install。CRF提供了各种语言的工具包,有java、python、perl等。我用的是python语言工具包,
所以还要安装python工具包:进入CRF++-0.58/python,python setup.py build ,(sudo) python setup.py install。安装完成后,可以打开python shell ,然后输入 import CRFPP,看看是否可以成功import,如果可以,就说明安装成功了。
CRF的example里有一个seg目录,里面是一个关于日文分词的例子。日文和中文很相似,所以用这个例子来训练model最合适了。
这里的训练集文件使用1998年1月份的《人民日报》语料 ,下载地址http://download.csdn.net/detail/u013378306/9740867
由于生成训练数据集后,有22M,测试的话,建议只用一部分。
中文语料部分:
- 19980101-01-001-001/m 迈向/v 充满/v 希望/n 的/u 新/a 世纪/n ——/w 一九九八年/t 新年/t 讲话/n (/w 附/v 图片/n 1/m 张/q )/w
- 19980101-01-001-002/m 中共中央/nt 总书记/n 、/w 国家/n 主席/n 江/nr 泽民/nr
- 19980101-01-001-003/m (/w 一九九七年/t 十二月/t 三十一日/t )/w
- 19980101-01-001-004/m 12月/t 31日/t ,/w 中共中央/nt 总书记/n 、/w 国家/n 主席/n 江/nr 泽民/nr 发表/v 1998年/t 新年/t 讲话/n 《/w 迈向/v 充满/v 希望/n 的/u 新/a 世纪/n 》/w 。/w (/w 新华社/nt 记者/n 兰/nr 红光/nr 摄/Vg )/w
为了得到适合拿来训练的数据集(4-tag标记),用到一个python脚本--make_crf_train_data.py:
- 词首,常用B表示
- 词中,常用M表示
- 词尾,常用E表示
- 单子词,常用S表示
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- # make_crf_train_data.py
- # 得到CRF++要求的格式的训练文件
- # 用法:命令行--python make_crf_train_data.py input_file output_file
- # 4 tags for character tagging: B(Begin), E(End), M(Middle), S(Single)
- import codecs
- import sys
- def character_tagging(input_file, output_file):
- input_data = codecs.open(input_file, 'r', 'gbk')
- 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:
- words=word.split("/");
- if len(words)>=2:
- xz = words[1]
- word=words[0]
- if len(word) == 1:
- output_data.write(word + "\t"+xz+"\tS\n")
- else:
- output_data.write(word[0] + "\t"+xz+"\tB\n")
- for w in word[1:len(word) - 1]:
- output_data.write(w + "\t"+xz+"\tM\n")
- output_data.write(word[len(word) - 1] + "\t"+xz+"\tE\n")
- output_data.write("\n")
- input_data.close()
- output_data.close()
- '''''if __name__ == '__main__':
- if len(sys.argv) != 3:
- print "pls use: python make_crf_train_data.py input output"
- sys.exit()
- input_file = sys.argv[1]
- output_file = sys.argv[2]
- character_tagging(input_file, output_file)'''
- character_tagging("199801.txt", "train.data")
执行
- python make_crf_train_data.py inputFilePath tag4OutputFilePath
tag4OutputFilePath 部分:
- 1 m E
- 迈 v B
- 向 v E
- 充 v B
- 满 v E
- 希 n B
- 望 n E
- 的 u S
- 新 a S
- 世 n B
- 纪 n E
- — w B
- — w E
- 一 t B
- 九 t M
- 九 t M
- 八 t M
- 年 t E
- 新 t B
- 年 t E
- 讲 n B
- 话 n E
- ( w S
- 附 v S
- 图 n B
- 片 n E
- 1 m S
- 张 q S
- ) w S
有了训练语料,接下来就可以利用crf的训练工具crf_learn来训练模型了,切换到CRF++0.58目录下,执行如下命令即可:
- crf_learn -f 3 -c 1.5 ./example/seg/template ../tag4OutputFilePath crf_model
得到crf_model即为训练好的模型文件。
编写py文件分词 :crf_segmenter.py
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- #crf_segmenter.py
- #用法:命令行输入--python crf_segmenter.py crf_model input_file output_file
- # 利用CRF自带的python工具包,对输入文本进行分词
- 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: #tag == 'S'
- output_data.write(' ' + char + ' ')
- output_data.write('\n')
- input_data.close()
- output_data.close()
- if __name__ == '__main__':
- if len(sys.argv) != 4:
- print "pls use: python crf_segmenter.py model input output"
- sys.exit()
- 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 input_file output_file
- 中华人民工和国,中国国家主席江泽民,讲述了三个代表重要思想,我们要解放思想,实事求是,抓住机遇,实现祖国的和平统一,繁荣富强。
output_file:
- 中华 人民 工 和国 , 中国 国家 主席 江 泽民 ,讲 述了 三个 代表 重要 思想 ,我 们要 解放 思想 , 实事 求是 ,抓 住机 遇, 实现 祖国 的 和 平统 一, 繁荣 富强 。
从上面的结果可以看出,效果也不比之前的maxent理想,但这里主要是我的电脑在作孽,由于原来的训练数据太大了,大概有400多万行数据,我在电脑上跑了三次,结果三次都导致了系统崩溃,最后一次我从晚上十点开始跑数据,一直到第二天凌晨一点还没好,后来我就去睡觉了,电脑开着让它继续运行,结果第二天醒来,程序又崩溃了,所以后来我就截取了训练数据里的大概五万行数据用来训练model,结果就导致了正确率不高的问题,其实如果电脑给力的话,分词准确率大概有96%。这也是CRF的一个特点,它需要大量的数据来进行训练才能得到理想的效果。
最终分词效率:
- === SUMMARY:
- === TOTAL INSERTIONS: 99
- === TOTAL DELETIONS: 30
- === TOTAL SUBSTITUTIONS: 156
- === TOTAL NCHANGE: 285
- === TOTAL TRUE WORD COUNT: 821
- === TOTAL TEST WORD COUNT: 890
- === TOTAL TRUE WORDS RECALL: 0.773
- === TOTAL TEST WORDS PRECISION: 0.713
- === F MEASURE: 0.742
- === OOV Rate: 0.141
- === OOV Recall Rate: 0.259
- === IV Recall Rate: 0.858
- ### blog_test_segment.utf8 99 30 156 285 821 890 0.773 0.713 0.742 0.141 0.259 0.858
- <pre code_snippet_id="2137761" snippet_file_name="blog_20170118_1_4933737" name="code" class="html"><pre code_snippet_id="2137761" snippet_file_name="blog_20170118_1_4933737"></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <link rel="stylesheet" href="http://static.blog.csdn.net/public/res-min/markdown_views.css?v=2.0">
- </pre>