• CRF++进行中文分词实例


    工具包: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 + "	S
    ")  
                else:  
                    output_data.write(word[0] + "	B
    ")  
                    for w in word[1:len(word)-1]:  
                        output_data.write(w + "	M
    ")  
                    output_data.write(word[len(word)-1] + "	E
    ")  
            output_data.write("
    ")  
        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 + "	B
    ")
        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 == "
    ":
                output_data.write("
    ")
            else:
                char_tag_pair = line.strip().split('	')
                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 + "	o	B").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('
    ')  
        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

  • 相关阅读:
    Shell 函数
    Shell 流程控制
    Shell test 命令
    Shell echo命令
    python 类、模块、包的区别
    postgresql vacuum table
    ssh连接断开后 shell进程退出
    ubuntu 搭建 svn服务器,使用http方式访问
    如何查看apache加载了哪些模块
    maven 的使用
  • 原文地址:https://www.cnblogs.com/gczr/p/10053768.html
Copyright © 2020-2023  润新知