用crf++工具进行自定义领域命名实体识别

网上的crf++教程很多,但小白还是花了不少时间去整合教程中的信息才得以应用,记录下本次步骤。

一、需求

大需求是抽取公开经济报告中的经济指标数据,其中重要一环是识别其中的经济指标专有名词(还有单位~)。

二、操作系统

window10

三、工具

python、crf++工具包

四、过程

4.1 原始文本

爬虫把标题(含了年份省份区县信息)和报告内容爬下来,存入txt,如下:

4.2 处理

本次大需求是抽取指标数据,故先将原始文本按句号和分号"。;"进行分句(先不加上","分句,保持主语连续便于后续操作),提取出含有数字的分句,减少处理量。处理后如下:

4.3 分词

采用jieba分词,本次再加上词性标注(后续crf++训练做特征用),并处理成cfr++的训练需求格式。代码及形式如下:

#读入分句,分词及词性标注,处理成训练需求的格式
for line in f.readlines():
    sentence_seged = jieba.posseg.cut(line.strip())
    for x in sentence_seged:
        f1.write(x.word + "\t" + x.flag + '\n')
初步	d
预测	vn
,	x
全市	n
实现	v
生产总值	n
240	m
亿元	m
,	x
增长	v
8.5	m
%	x
“	x
十二五	m
”	x
末	f
人均	j
GDP	eng
达到	v
1	x
万美元	m

4.4 标注

本次采用BMEWO标注(或BIESO),B(begin):实体的开始,M(middle):实体的中间,E(end):实体的结束,W(whole):单个分词就是实体,实体的全部,O(outside):界外值,非实体的任何一部分。标注在最后一列("\t"分隔),标注后如下:

训练文件 train.txt

初步	d	O
预测	vn	O
,	x	O
全市	n	O
实现	v	O
生产总值	n	W
240	m	O
亿元	m	O
,	x	O
增长	v	O
8.5	m	O
%	x	O
“	x	O
十二五	m	O
”	x	O
末	f	O
人均	j	B
GDP	eng	E
达到	v	O
1	x	O
万美元	m	O
,	x	O
人均	j	B
财政收入	n	E
突破	vn	O
1	x	O
万元	m	O

4.5 训练、测验及应用

首先是制作特征模板(template),crf++0.58工具包中有份template(在\example\seg路径下),如下:

搜索"crf++模板"了解template的含义和写法。学习后结合本次的特征情况采用如下模板

# Unigram
U00:%x[-2,0]
U01:%x[-1,0]
U02:%x[0,0]
U03:%x[1,0]
U04:%x[2,0]
U05:%x[-1,0]/%x[0,0]
U06:%x[0,0]/%x[1,0]

U10:%x[-2,1]
U11:%x[-1,1]
U12:%x[0,1]
U13:%x[1,1]
U14:%x[2,1]
U15:%x[-2,1]/%x[-1,1]
U16:%x[-1,1]/%x[0,1]
U17:%x[0,1]/%x[1,1]
U18:%x[1,1]/%x[2,1]

U20:%x[-2,1]/%x[-1,1]/%x[0,1]
U21:%x[-1,1]/%x[0,1]/%x[1,1]
U22:%x[0,1]/%x[1,1]/%x[2,1]

# Bigram
B

将工具包里的crf_learn.exe、crf_test.exe、libcrfpp.dll以及写好的模板文件template、训练文件train.txt、测试文件test.txt放在同一文件夹(下文称为A文件夹)下

模型训练:命令行下进入A文件夹,输入命令(crf_learn 参数 模板名 训练文件名 输出模型名),搜索"crf++参数"了解参数,本次采用默认参数。训练后A文件夹下生成model文件。

crf_learn template train.txt model

模型测试:类似训练的做法,命令行下输入命令(crf_learn 参数 模型名 测试文件名 > 输出文件名),成功后A文件夹下生成标注文件。

crf_test -m model test.txt > bz.txt

模型验证:检验模型的召回、F1等信息,本次不展开

模型应用:python执行命令行语句(同测试)调用模型并提取出其中的标注实体,代码及结果如下:

inputfile="inputfile.txt"#输入文件
predictfile="predictfile.txt"#输出模型标注预测文件
os.system("crf_test -m model "+inputfile+" > "+predictfile)#python执行命令行语句
df=pd.read_table(predictfile,sep='\t',header=None)
dflist=df[df[2]!="O"][[0,2]].values.tolist()#pandas提取标注非“O”的,1、3列
print("dflist:",dflist)
starr=[]#保存提取到的命名实体
for i in range(len(dflist)):
    temstr = ""
    if dflist[i][1]=="W":
        starr.append(dflist[i][0])
    if dflist[i][1]=="B":
        temstr=temstr+dflist[i][0]
        for j in range(i+1, len(dflist)):
            if dflist[j][1]=="M" or dflist[j][1]=="E":
                temstr = temstr + dflist[j][0]
            else:break
        starr.append(temstr)
print("提取到的命名实体:",starr)

五、后续

1、分词效果不太好,后续试试其他分词工具

2、尝试python中调用crf++工具

——————————————————————————————————————

2020.12.10更新后续啦 https://blog.csdn.net/m0_49621298/article/details/111006708

猜你喜欢

转载自blog.csdn.net/m0_49621298/article/details/109896619