[关闭]
@lianjizhe 2018-07-20T15:34:14.000000Z 字数 4948 阅读 7844

用CRF做命名实体识别(三)

CRF


欢迎大家访问我的简书以及我的博客
本博客所有内容以学习、研究和分享为主,如需转载,请联系本人,标明作者和出处,并且是非商业用途,谢谢!


摘要

本文主要是对近期做的命名实体识别做一个总结,会给出构造一个特征的大概思路,以及对比所有构造的特征对结构的影响。先给出我最近做出来的特征对比:

特征 F1值 精度 召回率
0.8399 0.8472 0.8327
字+词性+边界 0.8711 0.8839 0.8589
字+词性+边界+实体指示词 0.8856 0.9076 0.8649
字+词性+边界+特征词 0.8847 0.8990 0.8709
字+词性+边界+实体指示词 +特征词 0.8853 0.8994 0.8718
字+词性+边界+常用词 0.928 0.9382 0.9182
字+词性+边界+特征词+常用词 0.9293 0.9381 0.9207
字+词性+边界+实体指示词+特征词+常用词 0.9261 0.9334 0.9191

目录

  • 整体操作流程
  • 特征的构造思路
  • 用CRF++训练模型
  • 用CRF++测试模型并计算F1值

正文

1.整体操作流程

  • 构造特征,然后合并,格式要符合CRF++训练的格式
  • 撰写对应的特征模板
  • 用CRF++训练模型
  • 用CRF++测试模型并计算F1值

2.特征的构造思路

1) 构造词性

用jieba标注分词即可,直接调用jieba


2)构造词语边界特征

  1. B
  2. E
  3. B
  4. M
  5. M
  6. E
  7. W
  8. B
  9. M
  10. E

思路:

我们把句子先用jieba进行分词,然后遍历所有的词,用len函数判断这个词的长度,如果长度是1,那么标记为W,否则首部(word[0])标记为B,中间(word[1:-1])标记为M,尾部(word[-1])标记为E


3) 构造实体指示词特征

首先肯定会问什么是实体指示词呢?

在中文中,有些词的出现通常标志着该词周围很可能出现相应的命名实体,这样的词,我们称之为命名实体指示词。命名实体指示词是文本中非常有意义的上下文信息,可以有效的帮助识别命名实体。通常可以分为人名指示词、地名指示词和组织名指示词。
比如:温家宝总理主持了政府工作报告。这句话中“总理”这个词很大程度上指示着人名实体温家宝的出现 。

我用人民日报标注语料提取了人名,地名,组织名指示词。先给大家看一下地名指示词大概长什么样子

  1. ['向/p',
  2. '同胞/n',
  3. '和/c',
  4. '是/v',
  5. '发展/vn',
  6. '历史/n',
  7. '年/q',
  8. '人民/n',
  9. '建设/v',
  10. '有/v',
  11. '特色/n',
  12. '社会主义/n',
  13. '恢复/v',
  14. '对/p',
  15. '主权/n',
  16. ......]

建立一个实体指示词表的思路:

(1)从人民日报标记语料库中按顺序读取一个词 ;
(2)如果这个词是一个标记了的命名实体则转(3),否则转(1);
(3)读取当前词左边的 2 个词和右边的 2 个词,组成上下文词汇集合word_text,若当前词左边或者右边的词数少于 2 个,则取尽可能多个;
(4)如果当前词的标记为地名,则在备选地名指示词集合 Indication_l 中查找 word_text中的词,如果找到了,则相应词的频度加 1;否则,将此词加入到 Indication_l 集合 中,该词频度设为 1;
(5)如果当前词是语料中的最后一个词,转(6),否则转(1);
(6)统计备选备选地名指示词集合 Indication_l中所有词汇在单位语料中出现的频度 f;
(7)如果频度 f 小于阈值(我设置的是20) ,删除该词;

建立好实体指示词表之后就该构建实体指示词这个特征了

a) 先对每句话进行jieba分词,注意是不带标注的jieba分词
b) 遍历每个词,判断这个词是否在我们的实体指示词表里,在的话我们就做个标记是Y,不在的话就标记为N
c) 然后用len函数判断这个词的长度,依次写入我们的标记即可


4) 构造特征词

什么是特征词呢?
比如人名都是以姓氏开头的,所以它的特征词就是姓氏;组织名基本都是以特定的词汇结尾,比如公司,学校,集团等等;地名都是以省,市,国等特定的词结尾。这些都是特征词。这些特征词都可以从百度中查到,我们下载下来,这样就有三个文件。

思路

关于姓氏这个特征词的构造比较简单,因为它只有一个字,我们只需遍历每个字,然后判断这个字是不是在我们的姓氏表里,在的话标记为Y,不在的话标记为N。

  1. N
  2. N
  3. N
  4. N
  5. N
  6. N
  7. N
  8. N
  9. N
  10. N
  11. N
  12. N
  13. Y
  14. N
  15. N

关于地名和组织名的特征词构造有点麻烦,因为它是多个字。不过和上面构建实体指示词特征的思路一样
a) 先对每句话进行jieba分词,注意是不带标注的jieba分词
b) 遍历每个词,判断这个词是否在我们的特征词表里,在的话我们就做个标记是Y,不在的话就标记为N
c) 然后用len函数判断这个词的长度,依次写入我们的标记即可


5)构造常用词

什么是常用词呢?
比如常见的人名王伟,张伟等,常见的地名其实就是中国的所有地名,包括各种村什么的,还有常用的组织名,这些都可以从网上找到。这样就可以得到三个文件。
比如组织名"中共中央"就被找到,并标记为Y

  1. Y
  2. Y
  3. Y
  4. Y
  5. N
  6. N
  7. N
  8. N
  9. N
  10. N
  11. N
  12. N
  13. N
  14. N
  15. N

和上面构建实体指示词特征的思路一样
a) 先对每句话进行jieba分词,注意是不带标注的jieba分词
b) 遍历每个词,判断这个词是否在我们的常用词表里,在的话我们就做个标记是Y,不在的话就标记为N
c) 然后用len函数判断这个词的长度,依次写入我们的标记即可


6)构造标签
对文本进行jieba标注分词后,我们会得到每个词的词性,然后观察发现,人名标注词性为/nr,组织名是/nt,地名是/ns。这样我们就可以遍历所有的词,先判断词性,再结合前面构造边界的方法便可以构造了。

  1. O
  2. O
  3. O
  4. O
  5. O
  6. O
  7. O
  8. O
  9. O
  10. O
  11. O
  12. O
  13. B_TIME
  14. M_TIME
  15. M_TIME
  16. M_TIME
  17. E_TIME
  18. B_TIME
  19. E_TIME
  20. O
  21. O
  22. ( O
  23. O
  24. O
  25. O
  26. 1 O
  27. O
  28. ) O

7)构造好特征就是合并特征了,我用的是dataframe操作的
下面的特征顺序依次是
(字+词性+边界+地方指示词+组织名指示词+人名指示词+姓氏+地名特征词+组织名特征词+标签)

  1. v B N N N N N N O
  2. v E N N N N N N O
  3. nz B N N N N N N O
  4. nz M N N N N N N O
  5. nz M N N N N N N O
  6. nz E N N N N N N O
  7. uj W Y Y Y N N N O
  8. nz B N N N N N N O
  9. nz M N N N N N N O
  10. nz E N N N N N N O
  11. x W N N N N N N O
  12. x W N N N N N N O
  13. m B N N N N N N B_TIME
  14. m M N N N N N N M_TIME
  15. m M N N N N N N M_TIME
  16. m M N N N N N N M_TIME
  17. m E N N N N N N E_TIME
  18. t B Y N N N N N B_TIME
  19. t E Y N N N N N E_TIME
  20. n B N N Y N N N O
  21. n E N N Y N N N O
  22. ( x W N N N N N N O
  23. n B N N N N N N O
  24. n M N N N N N N O
  25. n E N N N N N N O
  26. 1 m W Y N N N N N O
  27. nr W N N N Y N N O
  28. ) x W N N N N N N O

合并好所有的特征之后这就是划分我们的数据集了,为了计算F1值我们还要把它们划分为训练集(70%)和测试集(30%)。


3.特征模板

比如下面的特征模板就是针对
(字+词性+边界+地方指示词+组织名指示词+人名指示词+姓氏+地名特征词+组织名特征词)这几个特征写的

  1. # Unigram
  2. U00:%x[-2,0]
  3. U01:%x[-1,0]
  4. U02:%x[0,0]
  5. U03:%x[1,0]
  6. U04:%x[2,0]
  7. U05:%x[-2,1]
  8. U06:%x[-1,1]
  9. U07:%x[0,1]
  10. U08:%x[1,1]
  11. U09:%x[2,1]
  12. U10:%x[0,0]/%x[0,1]
  13. U11:%x[0,0]/%x[1,0]
  14. U12:%x[0,0]/%x[-1,0]
  15. U13:%x[-1,0]/%x[0,1]
  16. U14:%x[0,0]/%x[1,1]
  17. U15:%x[-1,0]/%x[-1,1]
  18. U16:%x[-1,0]/%x[-2,0]
  19. U17:%x[-2,0]/%x[-2,1]
  20. U18:%x[1,0]/%x[2,0]
  21. U19:%x[-1,1]/%x[1,0]
  22. U20:%x[0,1]/%x[1,0]
  23. U21:%x[-2,1]/%x[-1,1]
  24. U22:%x[0,1]/%x[-2,1]
  25. U23:%x[-1,1]/%x[0,1]
  26. U24:%x[-1,1]/%x[1,1]
  27. U25:%x[0,1]/%x[1,1]
  28. U26:%x[0,1]/%x[2,1]
  29. U27:%x[1,1]/%x[2,1]
  30. U28:%x[-1,2]
  31. U29:%x[-2,2]
  32. U30:%x[-1,2]/%x[-2,2]
  33. U31:%x[0,1]/%x[-1,2]
  34. U32:%x[0,1]/%x[-2,2]
  35. U33:%x[0,1]/%x[1,2]
  36. U34:%x[0,0]/%x[-1,2]
  37. U35:%x[0,0]/%x[-2,2]
  38. U36:%x[0,0]/%x[1,2]
  39. U37:%x[0,1]/%x[-1,2]/%x[-2,2]
  40. U38:%x[-1,2]/%x[0,1]/%x[1,1]
  41. U39:%x[-1,2]/%x[-1,1]/%x[0,1]
  42. U40:%x[-1,2]/%x[0,1]/%x[0,0]
  43. U41:%x[-2,2]/%x[-1,2]/%x[0,1]
  44. U42:%x[-2,3]/%x[-1,3]/%x[1,3]%x[2,3]
  45. U43:%x[-2,4]/%x[-1,4]/%x[1,4]%x[2,4]
  46. U44:%x[-2,5]/%x[-1,5]/%x[1,5]%x[2,5]
  47. U45:%x[0,6]
  48. U46:%x[0,7]
  49. U47:%x[0,8]
  50. U48:%x[1,8]
  51. U49:%x[2,8]
  52. U50:%x[-2,5]/%x[-1,5]/%x[0,6]/%x[1,5]%x[2,5]
  53. U51:%x[-2,3]/%x[-1,3]/%x[0,7]
  54. U52:%x[-2,4]/%x[-1,4]/%x[0,8]
  55. # Bigram
  56. B

写特征模板首先是要把所有的特征都要罗列进去,然后特征模板里面比如说
“U50:%x[-2,5]/%x[-1,5]/%x[0,6]/%x[1,5]%x[2,5]”这句话的意思就是
当前字是否为姓氏,且它的左边和右边两个字是否为人名指示词

%x[-1,5]里面表示[-1行,5列]。0代表的是当前这个字,那么-1不就是代表前一个字么,而那个第五列指的就是第五个特征(注意我构造的特征的顺序,前面有说到),也就是对应的人名指示词这个特征了


4.用CRF++训练模型

具体操作就看我的简书里关于CRF++训练的操作,那里有详细的介绍。


5.用CRF++测试模型并计算F1值

调用sklearn库即可,非常简单
很重要的一点计算F1值一定记住把预测值和真实值都是O的全部删掉。比如说下面,倒数第二列是真实值,最后一列是预测值。为什么要删掉两列都是O的呢?因为整个数据集这样的太多了,会导致F1值偏高,我之前就把这部分算进去了,结果F1值为0.98,还沾沾自喜,以为自己好厉害

  1. v B N N N N N N O O
  2. v E N N N N N N O O
  3. ns B N N N N N N B_LOCATION B_LOCATION
  4. ns E N N N N N N E_LOCATION E_LOCATION
  5. n B Y N N Y N N O O
  6. n E Y N N N N N O O
  7. n B N N N N N N O O
  8. n E N N N N N N O O
  9. , x W N N N N N N O O
  10. nr B N N N Y N N B_PERSON B_PERSON
  11. nr M N N N N N N M_PERSON M_PERSON
  12. nr E N N N N N N E_PERSON E_PERSON
  13. v W Y Y Y N N N O O
  14. : x W N N N N N N O O
  15. x W N N N N N N O O
  16. ns B N N N N N N B_LOCATION B_LOCATION
  17. ns E N N N N N N E_LOCATION E_LOCATION
  18. d W Y Y Y N N N O O
  19. i B N N N N N N O O
  20. i M N N N N N N O O
  21. i M N N N N N N O O
  22. i E N N N N N N O O
  23. uv W Y N Y N N N O O

6.展望

用CRF做命名实体识别基本就做到这里了,我们发现(字+词性+边界+特征词+常用词)这几个特征可以达到比较好的效果,F1值为0.9293。再加入特征效果就会下降了,而且训练时间也会加长。后面打算用神经网络来做命名实体识别,目前主流方法是BILSTM-CRF,据说效果是很好的,网上有可以直接用的代码,回来操作一下。希望这篇博文会对大家有所帮助,至少可以帮大家入门命名实体识别。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注