简介
本文主要是我学习使用CRF++进行中文分词的一个记录,因此并没有CRF的背景知识与CRF++安装的相关内容。本文主要是按照中文分词入门之字标注法4中的相关内容进行。
过程
本文中所使用backoff2005数据集中的原始数据格式与CRF++所要求的格式不符,因此首先需要对数据集格式进行修改。
msr_training数据格式转换
在原始的msr_training.utf8的文件中的数据格式为如下所示
“ 人们 常 说 生活 是 一 部 教科书 , 而 血 与 火 的 战争 更 是 不可多得 的 教科书 , 她 确实 是 名副其实 的 ‘ 我 的 大学 ’ 。
“ 心 静 渐 知 春 似 海 , 花 深 每 觉 影 生 香 。
而在CRF++中则要求为每个字一行,按列的形式写,句子之间空一行,后面的列则为标记。在本文中,B为单词开头,M为单词中间,E为单词结尾,S为一个字为一个词。形式如下
“ S
人 B
们 E
常 S
说 S
生 B
通过下述程序即可完成此步,从而得到符合CRF++格式要求的msr_training.tagging4crf.utf8
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()
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)
# python make_crf_train.py ../icwb2-data/training/msr_training.utf8 msr_training.tagging4crf.utf8
得到model
有了符合要求的训练数据,还需要template去生成特征函数,从而得到model。本文中所使用的template为CRF++本身自带的example目录下seg例子中的template
# 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
然后通过一下命令即可得到相应model
crf_learn -f 3 -c 4.0 template msr_training.tagging4crf.utf8 crf_model
msr_test数据格式转换
在使用上述得到的model之前,还需要对msr_test同样进行数据格数的变化,与msr_train不同,此处msr_test中每个字的标记只需为B
扬 B
帆 B
远 B
东 B
做 B
转换的代码如下,转换后得到msr_test4crf.utf8
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")
output_data.write("\n")
input_data.close()
output_data.close()
if __name__ == '__main__':
if len(sys.argv) != 3:
print("pls use: python make_crf_test_data.py input output")
sys.exit()
input_file = sys.argv[1]
output_file = sys.argv[2]
character_split(input_file, output_file)
# python make_crf_test.py ../icwb2-data/testing/msr_test.utf8 msr_test4crf.utf8
测试
然后执行下述命令即可对test数据完成标注,得到标注结果msr_test4crf.tag.utf8
crf_test -m crf_model msr_test4crf.utf8 > msr_test4crf.tag.utf8
并且可以通过以下代码使用标注后的结果对test数据进行分词。
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()
if __name__ == '__main__':
if len(sys.argv) != 3:
print("pls use: python crf_data_2_word.py input output")
sys.exit()
input_file = sys.argv[1]
output_file = sys.argv[2]
character_2_word(input_file, output_file)
# python crf_data_2_word.py msr_test4crf.tag.utf8 msr_test4crf.tag2word.utf8
结果如下所示
扬帆 远东 做 与 中国 合作 的 先行
希腊 的 经济 结构 较 特殊 。
最后可以使用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: 1410
=== TOTAL DELETIONS: 1276
=== TOTAL SUBSTITUTIONS: 2432
=== TOTAL NCHANGE: 5118
=== TOTAL TRUE WORD COUNT: 106873
=== TOTAL TEST WORD COUNT: 107007
=== TOTAL TRUE WORDS RECALL: 0.965
=== TOTAL TEST WORDS PRECISION: 0.964
=== F MEASURE: 0.965
=== OOV Rate: 0.026
=== OOV Recall Rate: 0.650
=== IV Recall Rate: 0.974
### msr_test4crf.tag2word.utf8 1410 1276 2432 5118 106873 107007 0.965 0.964 0.965 0.026 0.650 0.974
接下来则是一次执行即可将测试数据转换为分词结果的代码,此代码要求在此之前已完成model
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"))
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)
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 ../icwb2-data/testing/msr_test.utf8 msr_test.seg.utf8
问题与解决
在这整个过程中都还算进行的比较顺利,可能在使用测试工具的命令时会出现没有权限的错误,此时只需对socre文件使用chmod改变权限