python 中文分词:正向最大匹配

本人虽然接触NLP时间不算短,但实际上代码能力还不是很强。上传该博客一是为了分享自己的代码(当然,我还没有能厉害到生成一个开源库让他人下载使用的程度,所以就没往github上传),二是也希望各位大神批评指正,从而也提升自己的能力。

关于中文分词,网上的理论早已铺天盖地,在此不赘述了。当然,其实我的数学也一般,看到那些理论什么的,脑袋也疼,主要是首先在理解上有困难,更别说转换为代码了。不过我发现,如果能理解已有的代码,那么理论也多少能更深入一些。不过想想第一份代码,不也是先理解了理论才有的么,所以我很佩服那些理论搞得懂、代码能力也强的人。

中文分词的最大匹配算是在这个领域比较基础而简单的了,涉及到的数学知识并不多,所以博主敢于发表。那些较为深入的算法博主也在琢磨中,任重而道远啊。

我为什么选择python这个语言呢?大概是因为我周围人用得少吧,我就想尝试突破,不过我也不讳言,我的C/C++,java等等高级语言用的也不多,虽说编程语言这个东西,基本上只要熟悉一个,其他的都好学,不过我在python上尝到了甜头,索性就用这个语言了。

下面对我的代码做简单的功能介绍,把测试语料和词典读进内存,假设最大词长为4,按最大匹配原则正向匹配,期间把测试语料按回车换行(’\r\n’)切分放入列表中,这样每句话就独立了,当然,最后的分词结果也是不含回车换行的。分词的结果写入到一个新文件中,词与词包括标点之间用两个空格(’ ‘)分开。分词结束后,把标准的分词结果,即金标分词结果(金标分词也是按照两个空格分开词的)读进内存,计算精确率、召回率以及F值。

整个程序运行对于五十万字左右的文本只需几秒就可完成,读者可尝试一下。

另外说明一下:
1.如果不设置编码方式,则一个中文字符的长度是3,如果设置为utf-8,则任意字符的长度都是1。(len()求长度)
2.本程序博主在python 3.6下运行。

博主对于面向对象的编程方式还在一点点深入,本想编成一个类再上传的。但是限于水平,我没有那么做。今后还需多加努力。

以下是代码:

MAXLEN=4
import codecs
#import sys
#语料
corpus=codecs.open('此处为测试语料路径','r','utf-8')
corpusReader=corpus.read()
corpus.close()

#字典
dic=codecs.open('此处为字典路径','r','utf-8')
diclines=dic.readlines()
dic.close()

#分别存储四字词、三字词和二字词
char_4=[]
char_3=[]
char_2=[]

for i in diclines:
    if len(i.split('\r\n')[0])==4:
        char_4.append(i.split('\r\n')[0])
    elif len(i.split('\r\n')[0])==3:
        char_3.append(i.split('\r\n')[0])
    else:
        char_2.append(i.split('\r\n')[0])

char_4=set(char_4)
char_3=set(char_3)
char_2=set(char_2)

sentences=[]
corpuslines=corpusReader.split('\r\n')
for senten in corpuslines:
    sentences.append(senten)    

print('Please wait a few seconds...')
temp=''
segResult=codecs.open('divide_result.txt','w','utf-8')

k=0
while k!=len(sentences):
    i=0           
    while i<len(sentences[k]):
        if i+MAXLEN<len(sentences[k]):
            possible_word=sentences[k][i:i+MAXLEN].split('\r\n')[0]
            if possible_word in char_4:
                temp+=possible_word+'  '
                #segResult.write(possible_word+'  ')
                i+=MAXLEN
                continue

        if i+3<len(sentences[k]):
            possible_word=sentences[k][i:i+3].split('\r\n')[0]
            if possible_word in char_3:
                temp+=possible_word+'  '
                #segResult.write(possible_word+'  ')
                i+=3
                continue

        if i+2<len(sentences[k]):
            possible_word=sentences[k][i:i+2].split('\r\n')[0]
            if possible_word in char_2:
                temp+=possible_word+'  '
                #segResult.write(possible_word+'  ')
                i+=2
                continue

        possible_word=sentences[k][i]
        temp+=possible_word+'  '
        #segResult.write(possible_word+'  ')
        i+=1
    #segResult.write('\r\n')
    k+=1

temp=temp.strip()
segResult.write(temp)
segResult.close()

print('Segmentation ends,calculating precision rate,recall rate and f-score.')
segResult=codecs.open('divide_result.txt','r','utf-8')
my=segResult.read()
segResult.close()

gold_corpus=codecs.open('此处为金标分词结果路径','r','utf-8')
gold=gold_corpus.read()
gold_corpus.close()

gold_split_enter=gold.split('\r\n')
gold=''
for i in gold_split_enter:
    gold+=i

gold_list=gold.strip().split('  ')
my_list=my.split('  ')
gold_len=len(gold_list)
my_len=len(my_list)
correct=0

gold_before=''
my_before=''

i=1
j=1
gold_before+=gold_list[0]
my_before+=my_list[0]
if gold_before==my_before and gold_list[0]==my_list[0]:
    correct+=1
    #sys.stdout.write(my_list[0])

while True:
    if gold_before==my_before and gold_list[i]==my_list[j]:
        correct+=1
        #sys.stdout.write(my_list[j])
        gold_before+=str(gold_list[i])
        my_before+=str(my_list[j])
        i+=1
        j+=1      
    elif len(gold_before)<len(my_before):
        gold_before+=str(gold_list[i])
        i+=1
    elif len(gold_before)>len(my_before):
        my_before+=str(my_list[j])
        j+=1
    elif gold_before==my_before and gold_list[i]!=my_list[j]:
        gold_before+=str(gold_list[i])
        my_before+=str(my_list[j])
        i+=1
        j+=1 
    if i>=len(gold_list) and j>=len(my_list):
        break

precision=correct/my_len
recall=correct/gold_len
f_score=2*precision*recall/(precision+recall)
print('precision rate:',precision)
print('recall rate:',recall)
print('f-score:',f_score)
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值