CRF的简单应用
程序员文章站
2022-07-09 23:11:44
之前简单研究了一下CRF的东西,但是原理还是知之甚少…但是大概想尝试一下它的实际作用,查案资料的过程中发现了所谓的中文分词的方法,尝试一下。
当然这个是我们的一般的语料,想要成...
之前简单研究了一下CRF的东西,但是原理还是知之甚少…但是大概想尝试一下它的实际作用,查案资料的过程中发现了所谓的中文分词的方法,尝试一下。
当然这个是我们的一般的语料,想要成为CRF++的训练数据还需要进行加工一番。写一个小程序解决一下,然后我们需要讨论一下训练数据中的二三列了!我们首先看一下example中的样例
Confidence NN B in IN O the DT B pound NN I is VBZ O widely RB O expected VBN O to TO O take VB O another DT B sharp JJ I dive NN I if IN O trade NN B figures NNS I
查看的资料中说第三列起到主要作用,第二列主要是词性,第三列我们是*发挥的,我们这样设计:
第二列我们标注是标点符号或者是文字,如果是标点符号标注为S,是文字则位W 第三列为分词的模式,采用4-tag标注法,(B(Begin,词首), E(End,词尾), M(Middle,词中), S(Single,单字词))举个栗子(随便举例,不一定准确啊,只是为了说明设计方法)
我 W S 说 W S : S S “ S S 我 W S 真 W S 是 W S 个 W S 大 W B 垃 W M 圾 W E ” S S
然后那么多材料写个程序处理一下
注意啊!!!我们这里不需要全部的内容,只要几十个txt就行了,只是实验而已,要是文本太大了model学习就十万年…
#_*_ coding:utf-8 _*_ import jieba import os import codecs goods_path = r'自己的目录哟\SogouC.reduced\Reduced\233' write_path = r'自己的目录哟\train.txt' test_txt = r'自己的目录哟\SogouC.reduced\Reduced\C000008\1107.txt' '''处理1行内容''' def handle_one_line(f,txt_dir,oneline): sign = ['“','”','。',',','!','—','@','#','¥','%','&','*','(',')','+','-','·','`','~',';',':','‘','’','<','>','《','》','?','/','[',']','{','}','|','\\',' ','、'] for i in range(len(sign)): sign[i] = sign[i].decode('gbk') seg_list = jieba.cut(oneline, cut_all=False) oneline = ' '.join(seg_list) #print oneline oneline = oneline.split(' ') #print oneline for content in oneline: if len(content)==0: continue elif len(content)==1: if content in sign: second = 'S' else: second = 'W' f.write(content[0]+' '+second+' S\n') else: f.write(content[0]+' W B\n') for i in range(1,len(content)-1): f.write(content[i]+' W M\n') f.write(content[len(content)-1]+' W E\n') '''处理1个txt''' def hadnle_one_txt(f,txt_dir): print "Prepare hand ",txt_dir temp_f = open(txt_dir,'r') content = temp_f.readlines() for oneline in content: oneline = oneline.replace(' ','').replace('\n','').replace(' ','') try: oneline=oneline.decode('gbk') except: print txt_dir,'is a UTF-8 file!' handle_one_line(f,txt_dir,oneline) print "Finish ",txt_dir temp_f.close() '''总函数,提取处理所有txt''' def handle(file_dir): global write_path f = codecs.open(write_path,'a','utf-8') for root, dirs, files in os.walk(file_dir): if len(files)==0: continue #print(root) #当前目录路径 #print(dirs) #当前路径下所有子目录 #print(files) #当前路径下所有非目录子文件 for txt_name in files: read_path = root+'\\'+txt_name hadnle_one_txt(f,read_path) f.close() if __name__ == '__main__': #handle(goods_path) if os.path.exists(write_path): os.remove(write_path) #hadnle_one_txt(test_txt)#测试使用来着 handle(goods_path)
然后我们的template基本上可以沿用之前的默认的,但是我们想要分词,肯定主要还是用到第一例和第二列的关系,这里我也不太会设计太复杂的,主要利用了第一列的内容…第二列就不太知道咋玩了(这个可以日后研究一下人家是怎么构造板子的)
# Unigram U00:%x[-3,0] U01:%x[-2,0] U02:%x[-1,0] U03:%x[0,0] U04:%x[1,0] U05:%x[2,0] U06:%x[3,0] U07:%x[-1,0]/%x[0,0] U08:%x[0,0]/%x[1,0] U09:%x[-2,0]/%x[-1,0]/%x[0,0] U10:%x[-1,0]/%x[0,0]/%x[1,0] U11:%x[0,0]/%x[1,0]/%x[2,0] U12:%x[-3,0]/x[-2,0]/%x[-1,0]/%x[0,0] U13:%x[-2,0]/x[-1,0]/%x[0,0]/%x[1,0] U14:%x[-1,0]/x[0,0]/%x[1,0]/%x[2,0] U15:%x[0,0]/x[1,0]/%x[2,0]/%x[3,0] # Bigram B
然后我们需要构造测试数据,简单构造一下,测试语句为
人群瞬间寂静下来,人们抬头看着,那架可能烧死了几十人的穿梭机轰鸣着从停泊区升起,拖着白色的尾迹直上高空,然后转向东方。人们似乎不敢相信眼前发生的事。只过了十几秒钟,又一架穿梭机从停泊区起飞,这次距离他们更近,轰鸣、火光和热浪让人群由僵滞陷人极度的狂乱中。接下来,第三架,第四架……停泊区的穿梭机相继强行发射,团团烈焰中,焦黑的人体拖着烟火在空中横飞,停泊区变成了火葬场! 老李躺在正中的一张床上,看上去很平静,云天明想到他们还没有告别过,心里越来越沉重。两个法律公证人在里面完成了公证程序,老李在公证书上签了字。公证人出来后,又有一个人进去为他讲解最后的操作程序。这人身着白大褂,不知是不是医生。他首先指着床前的一个大屏幕,问老李是否能看清上面显示的字,老李说可以后,他又让老一李试试是否能用右手移动床边的鼠标点击屏幕上的按钮,并特别说明,如果不方使.还有别的方式,老李试了试也可以。这时云天明想到.老一李曾告诉过他,自己从没用过电脑、取钱只能到银行排队,那么这是他有生第一次用鼠标了。穿白大褂的人接着告诉老李,屏幕上将显示一个问题,并重复显示五次,问题下面从0到5有六个按钮,每一次如果老李做肯定的回答,就按照提示按动一个按钮,提示的数字是1到5中随机的一个——之所以这样做,而没有用“是”或“否”按钮,是为了防止病人在无意识状态下反复按动同一个按钮;如果否定,则都是按0,这种情况下安乐程序将立刻中止。一名护士进去,把一个针头插到老李左臂上,针头通过一个软管与一台笔记本电脑大小的自动注射机相连。先前那名指导者掏出一个东西,打开层层密封,是一支小玻璃管,里面有淡黄色的液体,他小心地把那个玻璃管装到注射机上,然后和护士一起走出来。安乐室里只剩老李一人了。安乐程序正式开始,屏幕显示问题,同时由一个柔美的女声读出来:你要结束自己的生命吗?是,请按3键;否,请按0键。
处理数据的代码如下
#_*_ coding:utf-8 _*_ import jieba import os import codecs write_path_for_test = r'C:\Users\Administrator\Desktop\ACM比赛及其补题\test.txt' '''处理1行内容''' def handle_one_line(f,txt_dir,oneline): sign = ['“','”','。',',','!','—','@','#','¥','%','&','*','(',')','+','-','·','`','~',';',':','‘','’','<','>','《','》','?','/','[',']','{','}','|','\\',' ','、'] for i in range(len(sign)): sign[i] = sign[i].decode('gbk') seg_list = jieba.cut(oneline, cut_all=False) oneline = ' '.join(seg_list) #print oneline oneline = oneline.split(' ') #print oneline for content in oneline: if len(content)==0: continue elif len(content)==1: if content in sign: second = 'S' else: second = 'W' f.write(content[0]+' '+second+' S\n') else: f.write(content[0]+' W B\n') for i in range(1,len(content)-1): f.write(content[i]+' W M\n') f.write(content[len(content)-1]+' W E\n') if __name__ == '__main__': s1 = '人群瞬间寂静下来,人们抬头看着,那架可能烧死了几十人的穿梭机轰鸣着从停泊区升起,拖着白色的尾迹直上高空,然后转向东方。人们似乎不敢相信眼前发生的事。只过了十几秒钟,又一架穿梭机从停泊区起飞,这次距离他们更近,轰鸣、火光和热浪让人群由僵滞陷人极度的狂乱中。接下来,第三架,第四架……停泊区的穿梭机相继强行发射,团团烈焰中,焦黑的人体拖着烟火在空中横飞,停泊区变成了火葬场!' s2 = '老李躺在正中的一张床上,看上去很平静,云天明想到他们还没有告别过,心里越来越沉重。两个法律公证人在里面完成了公证程序,老李在公证书上签了字。公证人出来后,又有一个人进去为他讲解最后的操作程序。这人身着白大褂,不知是不是医生。他首先指着床前的一个大屏幕,问老李是否能看清上面显示的字,老李说可以后,他又让老一李试试是否能用右手移动床边的鼠标点击屏幕上的按钮,并特别说明,如果不方使.还有别的方式,老李试了试也可以。这时云天明想到.老一李曾告诉过他,自己从没用过电脑、取钱只能到银行排队,那么这是他有生第一次用鼠标了。穿白大褂的人接着告诉老李,屏幕上将显示一个问题,并重复显示五次,问题下面从0到5有六个按钮,每一次如果老李做肯定的回答,就按照提示按动一个按钮,提示的数字是1到5中随机的一个——之所以这样做,而没有用“是”或“否”按钮,是为了防止病人在无意识状态下反复按动同一个按钮;如果否定,则都是按0,这种情况下安乐程序将立刻中止。一名护士进去,把一个针头插到老李左臂上,针头通过一个软管与一台笔记本电脑大小的自动注射机相连。先前那名指导者掏出一个东西,打开层层密封,是一支小玻璃管,里面有淡黄色的液体,他小心地把那个玻璃管装到注射机上,然后和护士一起走出来。安乐室里只剩老李一人了。安乐程序正式开始,屏幕显示问题,同时由一个柔美的女声读出来:你要结束自己的生命吗?是,请按3键;否,请按0键。' if os.path.exists(write_path_for_test): os.remove(write_path_for_test) f = codecs.open(write_path_for_test,'a','utf-8') handle_one_line(f,write_path_for_test,s1) handle_one_line(f,write_path_for_test,s2) f.close()
之后执行
crf_learn -c 10.0 template train.txt model crf_test -m model test.txt >>result.txt
最后写个程序验证一下正确率…
#_*_ coding:utf-8 _*_ import jieba import os import codecs check_file = r'自己的目录哟\result.txt' f = codecs.open(check_file,'r','utf-8') total = 0 right = 0 wrong = 0 for lines in f.readlines(): temp = lines.replace('\r\n','').split(' ') if len(temp)<4: continue total+=1 if temp[2]==temp[3]: right+=1 else : wrong+=1 print '='*50 print 'Total number is ',total print 'Right number is ',right print 'Wrong number is ',wrong print 'Accuracy is ',str((right*1.0/total)*100)[:6]+'%' print '='*50 f.close()
测试结果看着有点高啊…讲道理是不应该的,但是毕竟这是一次小测试吧,而且错误的数量还是很多的…数据集也比较小,后面再进行研究吧。
上一篇: 给大龄个人站长的几点建议