使用HanLP进行分词和实体抽取
HanLP Github地址:https://github.com/hankcs/HanLP
HanLP文档地址:https://hanlp.hankcs.com/docs/api/hanlp/pretrained/index.html
多任务模型
首先我们来了解下HanLP有哪些预训练模型,其分为单任务模型和多任务模型,多任务模型就是可以同时执行多个任务,其模型的位置都在hanlp.pretrained.mtl这个包下,根据其文档说明
hanlp.pretrained.mtl.CLOSE_TOK_POS_NER_SRL_DEP_SDP_CON_ELECTRA_BASE_ZH
Electra(Clark et al.2020)在近源中文语料库上训练的联合tok、pos、ner、srl、dep、sdp和con模型的基础版本。
hanlp.pretrained.mtl.CLOSE_TOK_POS_NER_SRL_DEP_SDP_CON_ELECTRA_SMALL_ZH
Electra(Clark et al.2020)在近源中文语料库上训练的联合tok、pos、ner、srl、dep、sdp和con模型的迷你版本。
hanlp.pretrained.mtl.CLOSE_TOK_POS_NER_SRL_DEP_SDP_CON_ERNIE_GRAM_ZH
ERNIE(Xiao et al.2021)在近源汉语语料库上训练的联合tok、pos、ner、srl、dep、sdp和con模型的基础版本。
hanlp.pretrained.mtl.NPCMJ_UD_KYOTO_TOK_POS_CON_BERT_BASE_CHAR_JA
BERT(Devlin et al.2019)在NPCMJ/UD/Kyoto语料库上训练基本字符编码器,解码器包括tok、pos、ner、dep、con、srl。
hanlp.pretrained.mtl.OPEN_TOK_POS_NER_SRL_DEP_SDP_CON_ELECTRA_BASE_ZH
Electra(Clark et al.2020)在开源中文语料库上训练的联合tok、pos、ner、srl、dep、sdp和con模型的基础版本。
hanlp.pretrained.mtl.OPEN_TOK_POS_NER_SRL_DEP_SDP_CON_ELECTRA_SMALL_ZH
Electra(Clark et al.2020)在开源中文语料库上训练的联合tok、pos、ner、srl、dep、sdp和con模型的迷你版本。
hanlp.pretrained.mtl.UD_ONTONOTES_TOK_POS_LEM_FEA_NER_SRL_DEP_SDP_CON_XLMR_BASE
XLM-R(Conneau et al.2020)联合tok、pos、lem、fea、ner、srl、dep、sdp和con模型的基础版本,在UD和OntoNotes5语料库上进行训练。
hanlp.pretrained.mtl.UD_ONTONOTES_TOK_POS_LEM_FEA_NER_SRL_DEP_SDP_CON_MT5_SMALL
mT5(Xue et al.2021)联合tok、pos、lem、fea、ner、srl、dep、sdp和con模型的迷你版本,在UD和OntoNotes5语料库上进行训练。
然后根据github上的readme可以了解到这些简写的任务含义以及标注标准。
功能 | RESTful | 多任务 | 单任务 | 模型 | 标注标准 |
---|---|---|---|---|---|
分词 | 教程 | 教程 | 教程 | tok | 粗分/细分 |
词性标注 | 教程 | 教程 | 教程 | pos | CTB、PKU、863 |
命名实体识别 | 教程 | 教程 | 教程 | ner | PKU、MSRA、OntoNotes |
依存句法分析 | 教程 | 教程 | 教程 | dep | SD、UD、PMT |
成分句法分析 | 教程 | 教程 | 教程 | con | Chinese Tree Bank |
语义依存分析 | 教程 | 教程 | 教程 | sdp | CSDP |
语义角色标注 | 教程 | 教程 | 教程 | srl | Chinese Proposition Bank |
抽象意义表示 | 教程 | 暂无 | 教程 | amr | CAMR |
另外,通过print(hanlp.pretrained.mtl.ALL)
可以直接打印所有的模型名称,并且附有模型文件下载链接。
模型加载和使用
我们选择上面的一种模型
1 | import hanlp |
第一次运行时,会自动下载模型文件,下载地址和存储路径会在控制台显示,存储路径一般在C盘:
C:\Users\username\AppData\Roaming\hanlp……
也可以自己下载文件到指定目录解压,然后从指定目录加载,但是要注意解压的文件夹名称要和压缩文件名称一致,例如
1 | hanlp.load( |
下载好之后,可以查看该模型支持哪些任务:
1 | tasks = list(HanLP.tasks.keys()) |
tok/fine: tok是分词, coarse
为粗分,fine
为细分。 。 ‘/‘前面是任务,后面是标注标准
分词和自定义词典
分词测试
1 | import hanlp |
这里设置tasks=”tok”默认是细粒度的分词,如果设置tasks=”tok/coarse”,可以得到粗粒度的分词结果,设置tasks=”tok*”可以得到两种分词结果。
以下是粗粒度的分词结果:
1 | ['本', '院', '定于', '2022', '年', '6', '月', '1', '日', '上午', '09', '时', '00', '分', '在', '普洱市中级人民法院第三法庭', '公开', '开庭', '审理', '原告', '中国音像著作权集体管理协会', '与', '被告', '普洱帝都娱乐有限公司', '著作权', '权', '属', '、', '侵权', '纠纷', '一', '案', '。'] |
自定义词典
在应用于特定领域时,一般我们都会有一些领域词,而hanlp这种通用的模型没办法提取出领域词,我们希望可以添加这样一个词表,可以让hanlp在分词时,将这些词作为一个分词结果。
我们可以通过这种方式自定义词典
1 | def tokenizer(self, data): |
强制模式优先输出正向最长匹配到的自定义词条,与大众的朴素认知不同,词典优先级最高未必是好事,极有可能匹配到不该分出来的自定义词语,导致歧义。
另外还有一种合并模式,合并模型优先级低于统计模型,即dict_combine
会在统计模型的分词结果上执行最长匹配并合并匹配到的词条。一般情况下,推荐使用该模式,使用方式如下
1 | tok.dict_combine = {'市中级人民法院', '开庭审理'} |
合并模型添加的词并不一定总能分词成功,因为还是以统计为主,比如这里市中级人民法院就没有分词成功。
另外如果你的自定义词典中的词含有空格、制表符等,可以通过tuple的形式添加
tok.dict_combine = {('iPad', 'Pro')}
如果想要获取分词在原文本的位置信息,可以这样配置
tok.config.output_spans = True
返回格式为三元组(单词,单词的起始下标,单词的终止下标),下标以字符级别计量。
实体抽取和自定义实体词典
接下来我们用它来对一段文本进行实体抽取(实体抽取任务中包含分词)
实体抽取测试
1 | class HanLPModel: |
这里返回的实体抽取结果,每个四元组表示[命名实体, 类型标签, 起始下标, 终止下标],下标指的是命名实体在单词数组中的下标,单词数组默认为第一个以tok
开头的数组
这里执行ner抽取任务时,设置tasks=”ner”,默认是MSRA标准,如果想要执行特定标注的ner任务,可以这样调用:tasks=”ner/pku”,同时执行所有标准的ner任务:tasks=”ner*”。
接下来我们再做一个测试:
1 | content = """本院定于2022年6月1日上午09时00分在普洱市中级人民法院第三法庭公开开庭审理原告中国音像著作权集体管理协会与被告普洱帝都娱乐有限公司著作权权属、侵权纠纷一案。""" |
自定义实体词典
像自定义分词一样,很多时候特定领域有自己的实体,也同样可以通过添加自定义词典的形式来提高抽取效果。
这里分为白名单词典和强制词典,与分词的合并模型和强制模式类似。
1 | def add_white_list(self): |
白名单词典通过ner.dict_whitelist
添加,这里添加的实体除了最后一个”院定”的实体,基本在抽取结果中都成功抽取了,这里的”院定”其实就是做测试用的,肯定不是实体,也表示白名单词典并不一定会被输出,优先级低于统计。
强制词典的添加比较麻烦,需要了解标注规则。
BIO
- B stands for ‘beginning‘ (signifies beginning of an Named Entity, i.e. NE)
- I stands for ‘inside‘ (signifies that the word is inside an NE)
- O stands for ‘outside‘ (signifies that the word is just a regular word outside of an NE)
BIOES
- B stands for ‘beginning‘ (signifies beginning of an NE)
- I stands for ‘inside‘ (signifies that the word is inside an NE)
- O stands for ‘outside‘ (signifies that the word is just a regular word outside of an NE)
- E stands for ‘end‘ (signifies that the word is the end of an NE)
- S stands for ‘singleton‘(signifies that the single word is an NE )
比如这里把原告和被告添加为ROLE实体
1 | ner = self.HanLP['ner/msra'] |
但是想把1日
添加为一个时间实体没有成功,有知道如何添加的可以留言~
另外还可以添加黑名单词典,黑名单中的词语绝对不会被当做命名实体,比如这里1被识别为实体,将其从实体中移除:
1 | def add_black_list(self): |