——————————————
王老师就留了课后作业,让算一下训练出来结果的P(精准率)、R(召回率)、F(调和数),以展示我们所应用CRF机器学习的显著效果。
1.模板
首先模板是最简单的模板,没有加入什么特征。所以训练出来能达到70%我就很满意了。
模板如下:
# Unigram
U01:%x[-2,0]
U02:%x[-1,0]
U03:%x[0,0]
U04:%x[1,0]
U05:%x[2,0]
U06:%x[-2,0]/%x[-1,0]
U07:%x[-1,0]/%x[0,0]
U08:%x[0,0]/%x[1,0]
U09:%x[1,0]/%x[2,0]
# Bigram
B
确实没什么。。
2.语料
我们全班标注了数据科学相关招聘信息中的需求实体词,如:“本科”、“硕士及以上”、“Java”、“Python”、“团队协作”……等等(一句话中你看什么是需求就取出来这种)
收齐全班四十多人的结果,最后转化一下成为BEMS的格式。
大 B
专 M
及 M
以 M
上 E
学 S
历 S
, S
要 S
有 S
一 S
定 S
的 S
逻 B
辑 M
思 M
维 E
, S
热 S
爱 S
互 B
联 M
网 E
工 S
作 S
。 S
CRF封装的真是很好,跑完就得到了如下的结果(部分)。第一、二列同上,第三列为机器学习后的结果。
大 B B
专 M M
及 M S
以 M S
上 E S
学 S S
历 S S
, S S
要 S S
有 S S
一 S S
定 S S
的 S S
逻 B B
辑 M M
思 M M
维 E E
, S S
热 S S
爱 S S
互 B B
联 M M
网 E E
工 S S
作 S S
。 S S
4.P、R、F是什么?怎么算?
下面是今天的主要挑战部分,如何根据我们的结果来计算P、R、F值呢?
第一,我们要知道这里的的P、R、F是什么?这里极力推荐这篇博客(点击连接)。
P(查准率or准确率):分母是第二列机器识别出来的个数,分子是第二列识别出来中正确的个数。精确率和自己比较。
R(查全率or召回率):分母是第一列中识别出来的个数,分子是第二列识别出来中正确的个数。召回率和标准答案比较。
F(调和平均数):综合P、R的共同指标。
第二,回到我们的第三节的例子中,怎么样算是识别出来了呢?
1)情况一:
工 S S 作 S S
像这种S S对应的算是识别出来的。因为答案是“错”,机器说的也是“错”,那么机器不就作对了么。
2)情况二:
逻 B B 辑 M M 思 M M 维 E E
像这种标签一一对应的,也是机器答对了的情况。
那么,除了上面两种情况,其他都不算识别出来。
最后,我们就可以进行算法转化成程序了。要做的很简单,
1.分别记录第一列、第二列所识别出来的个数。
2.识别一、二两种情况的个数。
3.计算。
(下面附上没有算法只有暴力匹配的Python代码)
# coding=utf-8 # author:Zzh-748 # 程序功能:计算有两列对照的结果文件的P、R、F值。 def count_right_term(list1,list2): # 核心 flag=False c_r_term=0 # 记录正确数 for i in range(len(list1)): tags=list1[i]+list2[i] # print(tags,end=' ') if flag==False: if tags=='SS': # 识别第一种情况 c_r_term+=1 # print('------------ss') elif tags=='BB': flag=True # 开始判断是否为识别出第二种情况 # print() else: # print() pass else: if ((tags)!='MM' and (tags)!='EE') and 'E' not in tags: flag=False # 识别错误,退出识别 # print() elif (tags)=='EE': flag=False # 识别结束,退出识别 # print("------------BMES") c_r_term+=1 else: # print() pass # go on... return c_r_term def count_B_and_S(list_n): # 此处以B和S的总数作为识别出的个数 count=0 for term in list_n: if term=='S' or term=='B': count+=1 return count def Cal_PRF(lines): list1=[] list2=[] for line in lines: if line!='\n': list1.append(line.split('\t')[1]) # 记录第一列 list2.append(line.split('\t')[2].replace('\n','')) # 记录第二列 print('list1 and list2 --- Loaded..') li_count1=count_B_and_S(list1) # R 的分母 li_count2=count_B_and_S(list2) # P 的分母 # print(li_count1,li_count2) right_term=count_right_term(list1,list2) # 分子 # P、R、F计算核心 P=right_term/li_count2 R=right_term/li_count1 F=2*P*R/(P+R) return {'P':P,'R':R,'F':F} #返回字典格式的PRF值 def main(): with open("result.txt","r",encoding='utf-8') as fr: lines=fr.readlines() result=Cal_PRF(lines) print('P:',result['P'],'\nR:',result['R'],'\nF:',result['F']) if __name__=="__main__": main()
main()中打开的“result.txt”为需要计算PRF的文本。
结果:更多的特征
list1 and list2 --- Loaded.. P: 0.8 R: 0.9411764705882353 F: 0.8648648648648648
至此,PRF值的计算过程就算告一段落了。接下来的工作是对模版进行优化,加入新的特征等等。