@lianjizhe
2018-07-20T23:34:14.000000Z
字数 4948
阅读 12740
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值
- 构造特征,然后合并,格式要符合CRF++训练的格式
- 撰写对应的特征模板
- 用CRF++训练模型
- 用CRF++测试模型并计算F1值
1) 构造词性
用jieba标注分词即可,直接调用jieba
2)构造词语边界特征
迈 B
向 E
充 B
满 M
希 M
望 E
的 W
新 B
世 M
纪 E
思路:
我们把句子先用jieba进行分词,然后遍历所有的词,用len函数判断这个词的长度,如果长度是1,那么标记为W,否则首部(word[0])标记为B,中间(word[1:-1])标记为M,尾部(word[-1])标记为E
3) 构造实体指示词特征
首先肯定会问什么是实体指示词呢?
在中文中,有些词的出现通常标志着该词周围很可能出现相应的命名实体,这样的词,我们称之为命名实体指示词。命名实体指示词是文本中非常有意义的上下文信息,可以有效的帮助识别命名实体。通常可以分为人名指示词、地名指示词和组织名指示词。
比如:温家宝总理主持了政府工作报告。这句话中“总理”这个词很大程度上指示着人名实体温家宝的出现 。
我用人民日报标注语料提取了人名,地名,组织名指示词。先给大家看一下地名指示词大概长什么样子
['向/p',
'同胞/n',
'和/c',
'是/v',
'发展/vn',
'历史/n',
'年/q',
'人民/n',
'建设/v',
'有/v',
'特色/n',
'社会主义/n',
'恢复/v',
'对/p',
'主权/n',
......]
建立一个实体指示词表的思路:
(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。
中 N
共 N
中 N
央 N
总 N
书 N
记 N
、 N
国 N
家 N
主 N
席 N
江 Y
泽 N
民 N
关于地名和组织名的特征词构造有点麻烦,因为它是多个字。不过和上面构建实体指示词特征的思路一样
a) 先对每句话进行jieba分词,注意是不带标注的jieba分词
b) 遍历每个词,判断这个词是否在我们的特征词表里,在的话我们就做个标记是Y,不在的话就标记为N
c) 然后用len函数判断这个词的长度,依次写入我们的标记即可
5)构造常用词
什么是常用词呢?
比如常见的人名王伟,张伟等,常见的地名其实就是中国的所有地名,包括各种村什么的,还有常用的组织名,这些都可以从网上找到。这样就可以得到三个文件。
比如组织名"中共中央"就被找到,并标记为Y
中 Y
共 Y
中 Y
央 Y
总 N
书 N
记 N
、 N
国 N
家 N
主 N
席 N
江 N
泽 N
民 N
和上面构建实体指示词特征的思路一样
a) 先对每句话进行jieba分词,注意是不带标注的jieba分词
b) 遍历每个词,判断这个词是否在我们的常用词表里,在的话我们就做个标记是Y,不在的话就标记为N
c) 然后用len函数判断这个词的长度,依次写入我们的标记即可
6)构造标签
对文本进行jieba标注分词后,我们会得到每个词的词性,然后观察发现,人名标注词性为/nr,组织名是/nt,地名是/ns。这样我们就可以遍历所有的词,先判断词性,再结合前面构造边界的方法便可以构造了。
迈 O
向 O
充 O
满 O
希 O
望 O
的 O
新 O
世 O
纪 O
— O
— O
一 B_TIME
九 M_TIME
九 M_TIME
八 M_TIME
年 E_TIME
新 B_TIME
年 E_TIME
讲 O
话 O
( O
附 O
图 O
片 O
1 O
张 O
) O
7)构造好特征就是合并特征了,我用的是dataframe操作的
下面的特征顺序依次是
(字+词性+边界+地方指示词+组织名指示词+人名指示词+姓氏+地名特征词+组织名特征词+标签)
迈 v B N N N N N N O
向 v E N N N N N N O
充 nz B N N N N N N O
满 nz M N N N N N N O
希 nz M N N N N N N O
望 nz E N N N N N N O
的 uj W Y Y Y N N N O
新 nz B N N N N N N O
世 nz M N N N N N N O
纪 nz E N N N N N N O
— x W N N N N N N O
— x W N N N N N N O
一 m B N N N N N N B_TIME
九 m M N N N N N N M_TIME
九 m M N N N N N N M_TIME
八 m M N N N N N N M_TIME
年 m E N N N N N N E_TIME
新 t B Y N N N N N B_TIME
年 t E Y N N N N N E_TIME
讲 n B N N Y N N N O
话 n E N N Y N N N O
( x W N N N N N N O
附 n B N N N N N N O
图 n M N N N N N N O
片 n E N N N N N N O
1 m W Y N N N N N O
张 nr W N N N Y N N O
) x W N N N N N N O
合并好所有的特征之后这就是划分我们的数据集了,为了计算F1值我们还要把它们划分为训练集(70%)和测试集(30%)。
比如下面的特征模板就是针对
(字+词性+边界+地方指示词+组织名指示词+人名指示词+姓氏+地名特征词+组织名特征词)这几个特征写的
# Unigram
U00:%x[-2,0]
U01:%x[-1,0]
U02:%x[0,0]
U03:%x[1,0]
U04:%x[2,0]
U05:%x[-2,1]
U06:%x[-1,1]
U07:%x[0,1]
U08:%x[1,1]
U09:%x[2,1]
U10:%x[0,0]/%x[0,1]
U11:%x[0,0]/%x[1,0]
U12:%x[0,0]/%x[-1,0]
U13:%x[-1,0]/%x[0,1]
U14:%x[0,0]/%x[1,1]
U15:%x[-1,0]/%x[-1,1]
U16:%x[-1,0]/%x[-2,0]
U17:%x[-2,0]/%x[-2,1]
U18:%x[1,0]/%x[2,0]
U19:%x[-1,1]/%x[1,0]
U20:%x[0,1]/%x[1,0]
U21:%x[-2,1]/%x[-1,1]
U22:%x[0,1]/%x[-2,1]
U23:%x[-1,1]/%x[0,1]
U24:%x[-1,1]/%x[1,1]
U25:%x[0,1]/%x[1,1]
U26:%x[0,1]/%x[2,1]
U27:%x[1,1]/%x[2,1]
U28:%x[-1,2]
U29:%x[-2,2]
U30:%x[-1,2]/%x[-2,2]
U31:%x[0,1]/%x[-1,2]
U32:%x[0,1]/%x[-2,2]
U33:%x[0,1]/%x[1,2]
U34:%x[0,0]/%x[-1,2]
U35:%x[0,0]/%x[-2,2]
U36:%x[0,0]/%x[1,2]
U37:%x[0,1]/%x[-1,2]/%x[-2,2]
U38:%x[-1,2]/%x[0,1]/%x[1,1]
U39:%x[-1,2]/%x[-1,1]/%x[0,1]
U40:%x[-1,2]/%x[0,1]/%x[0,0]
U41:%x[-2,2]/%x[-1,2]/%x[0,1]
U42:%x[-2,3]/%x[-1,3]/%x[1,3]%x[2,3]
U43:%x[-2,4]/%x[-1,4]/%x[1,4]%x[2,4]
U44:%x[-2,5]/%x[-1,5]/%x[1,5]%x[2,5]
U45:%x[0,6]
U46:%x[0,7]
U47:%x[0,8]
U48:%x[1,8]
U49:%x[2,8]
U50:%x[-2,5]/%x[-1,5]/%x[0,6]/%x[1,5]%x[2,5]
U51:%x[-2,3]/%x[-1,3]/%x[0,7]
U52:%x[-2,4]/%x[-1,4]/%x[0,8]
# Bigram
B
写特征模板首先是要把所有的特征都要罗列进去,然后特征模板里面比如说
“U50:%x[-2,5]/%x[-1,5]/%x[0,6]/%x[1,5]%x[2,5]”这句话的意思就是
当前字是否为姓氏,且它的左边和右边两个字是否为人名指示词%x[-1,5]里面表示[-1行,5列]。0代表的是当前这个字,那么-1不就是代表前一个字么,而那个第五列指的就是第五个特征(注意我构造的特征的顺序,前面有说到),也就是对应的人名指示词这个特征了
具体操作就看我的简书里关于CRF++训练的操作,那里有详细的介绍。
调用sklearn库即可,非常简单
很重要的一点计算F1值一定记住把预测值和真实值都是O的全部删掉。比如说下面,倒数第二列是真实值,最后一列是预测值。为什么要删掉两列都是O的呢?因为整个数据集这样的太多了,会导致F1值偏高,我之前就把这部分算进去了,结果F1值为0.98,还沾沾自喜,以为自己好厉害
谈 v B N N N N N N O O
到 v E N N N N N N O O
亚 ns B N N N N N N B_LOCATION B_LOCATION
洲 ns E N N N N N N E_LOCATION E_LOCATION
金 n B Y N N Y N N O O
融 n E Y N N N N N O O
风 n B N N N N N N O O
波 n E N N N N N N O O
, x W N N N N N N O O
董 nr B N N N Y N N B_PERSON B_PERSON
建 nr M N N N N N N M_PERSON M_PERSON
华 nr E N N N N N N E_PERSON E_PERSON
说 v W Y Y Y N N N O O
: x W N N N N N N O O
“ x W N N N N N N O O
香 ns B N N N N N N B_LOCATION B_LOCATION
港 ns E N N N N N N E_LOCATION E_LOCATION
将 d W Y Y Y N N N O O
坚 i B N N N N N N O O
定 i M N N N N N N O O
不 i M N N N N N N O O
移 i E N N N N N N O O
地 uv W Y N Y N N N O O
用CRF做命名实体识别基本就做到这里了,我们发现(字+词性+边界+特征词+常用词)这几个特征可以达到比较好的效果,F1值为0.9293。再加入特征效果就会下降了,而且训练时间也会加长。后面打算用神经网络来做命名实体识别,目前主流方法是BILSTM-CRF,据说效果是很好的,网上有可以直接用的代码,回来操作一下。希望这篇博文会对大家有所帮助,至少可以帮大家入门命名实体识别。