• Windows下CRF++进行中文人名识别的初次尝试



    语料来自1998年1月份人民日报语料


    1 语料处理


    1.1 原始语料数据格式

    语料中,句子已经被分词好,并且在人名后以“/”标注了“nr”表示是人名,其他非人名的分词没有进行标注

    1.2 CRF++要求语料的格式

    训练语料至少应具有两列,列间由空格或制表位间隔,且所有行(空行除外)必须具有相同的列数,句子间使用空行间隔

    1.3 对原始数据进行处理

    CRF++可以有多个特征,举例如下图

     

     本次实验为了熟悉采用CRF++及进行中文人名标注,故将语料中的每一个单字作为特征,并进行BIEO标注,举例如下图

     

     采用Python将原始数据读入,并将其格式转化为标准的两个列向量的格式,举例如下

     

     代码如下

    # coding:utf-8
    import codecs
    fin = codecs.open("data_to_final.txt", "r", "utf-8")
    f = codecs.open("data_to_final_to_crf.txt", "a", "utf-8")
    row = 1
    while (True):
        text = fin.readline()
        if (text == ""):
            break
        tmp = text.split(" ")
        n = len(tmp)
        for i in range(0, n - 1):
            if 'nr' in tmp[i]:
                word = tmp[i].split('/')
                tmpword = word[0]
                wordlist = list(tmpword)
                m = len(wordlist)
                if m == 1:
                    f.write(wordlist[0] + ' S
    ')
                elif m == 2:
                    f.write(wordlist[0] + ' B
    ')
                    f.write(wordlist[1] + ' E
    ')
                else:
                    f.write(wordlist[0] + ' B
    ')
                    for k in range(1, m -1):
                        f.write(wordlist[k] + ' I
    ')
                    f.write(wordlist[m-1] + ' E
    ')
            else:
                tmpword = tmp[i]
                wordlist = list(tmpword)
                m = len(wordlist)
                for k in range(0, m):
                    f.write(wordlist[k] + ' O
    ')
        f.write('
    ')
        print "当前执行到第", row, ""
        row += 1
    f.close()

    1.4 遇到的问题及解决办法

    问题:由于在处理预料的时候是以空格来取词的,但是每句话的最后由于直接是换行符号(“ ”),缺少一个空格导致每句话的最后的一个词无法被读入而使数据缺失,举例如下

     

    解决办法:再写一个小程序对最原始的语料进行加工,具体的就是在每一行的句尾加上一个空格。再将加工后的数据用于转换格式,解决问题

    代码如下

    # coding:utf-8
    import codecs
    fin = codecs.open("data_nr.txt", "r")
    f = codecs.open("data_to_final.txt", "a")
    row = 1
    while (True):
        text = fin.readline()
        if (text == ""):
            break
        tmp = list(text)
        tmp.insert(-1 ,' ')#每行后加一个空格
        f.writelines(tmp)
        print "当前执行到第", row, ""
        row += 1
    f.close() 

    2 使用CRF++进行实验


    将语料数据集分成两份(8:2的比例),将大的集合定义为训练数据集,小的集合定义为测试数据集合

    2.1 构建模板

    新建一个名为template的文件用于构建模板,由于本实验只采用了字为特征,所以创建的模板也很简单,如下图

     

    2.2 进行学习

    采用相应的命令进行学习

    crf_learn template data_nr_train_to_crf.data model

    经历了几分钟,模型就已经训练好了,如下图

     

    2.3 进行测试

    将事先准备好的测试语料用于CRF++,使用相应命令进行测试,将结果保存到result文件中

     crf_test -m model data_nr_test_to_crf.data > result

    得到的结果格式是在原有的两列后再增加一列,是通过训练的模型对测试数据中的文字进行的标注结果,举例如下

     

    2.4 遇到的问题及解决办法

    问题:在进行第一次学习的时候,出现程序中途停止的问题,如下

     

    解决办法:通过查阅网络资源与进行小数据集合的实验发现导致此问题的原因应该就是,由于实验环境是在Windows的环境中进行的,数据集太大会导致程序终止。所以几次尝试后,将训练数据集减小为原来的3/4左右,再次进行学习,程序运行成功,解决问题。


    3 评估


    验证就是比较result文档的后两列数据,统计相同的标签个数或不同的个数,从而得到准确率、召回率、F1值。

    3.1 采用conlleval.pl脚本文件进行评估

    使用此文件的前提是要在机器上搭建perl环境,是在perl官方网站进行下载并安装。准备好之后,采用相关命令进行验证操作,并将结果写入evaluation中

    perl conlleval.pl < result > evaluation

    3.2 评估结果

    打开evaluation文件,如图3-2所示,可以看到准确率为99.66%,精确率为95.12%,召回率为83.96%,F1值为89.19,导致这样的结果显然就是此次实验只用单字作为特征

     

    3.3 遇到的问题及解决办法

    问题:第一次进行评估的时候,程序运行报错,如下

     

    解决办法:查阅相关资料,得知CRF++输出的测试结果中,相邻两行间是制表符(“ ”),而conlleval.pl要求相邻列间必须是空格,于是通过Ultraedit软件的替换功能将所有制表符替换为空格,如图3-4所示。保存文件后进行验证,解决问题。

     

    4 总结

    本次实验核心工具是CRF++,用于评估的工具采用了conlleval.pl,在语料预处理阶段采用Python编写的小程序

    由于采用的单字特征,导致召回率稍低,后续可以考虑选取更多的特征(比如添加先验概率分布作为另一个特征等),来进行实验

  • 相关阅读:
    django 1.9.7 css控制模板样式
    python -- 判断给定的参数是否是地理位置的经度和纬度
    有恃无恐
    不知不觉
    vscode 编写Python走过的坑
    Python的从头再来
    【初赛】数学题错题总结
    【初赛】选择题总结
    20175317 《Java程序设计》第四周学习总结
    20175317 《Java程序设计》第三周学习总结
  • 原文地址:https://www.cnblogs.com/xinglichao/p/8902115.html
Copyright © 2020-2023  润新知