互信息和左右熵的新词发现(笔记)

推荐:http://spaces.ac.cn/archives/3491/

http://www.matrix67.com/blog/archives/5044

http://www.hankcs.com/nlp/new-word-discovery.html


其实很多人都已经知道这个算法了,是由Matrix67牛人提出来的,实现的方式也有很多人解决了。我只是写个最简单的介绍和实现方式给自己做做笔记罢。该算法最主要是基于互信息和左右熵的计算规则,而这两个概念都是出自信息论的范畴,其一者称内部凝和度,其二者称外部自由度或者边界自由度。

这里有三个阈值

第一是最小互信息,因为互信息越大说明相关度越大,将n-gram分好的词计算互信息,如果低于阈值,则说明不能成词。

第二是最小熵值,因为熵也是越大说明周边词越丰富,计算其左熵和右熵的最小值,如果最小值低于阈值,则说明不能成词。

第三个是最少出现次数,为什么有这个数呢?假设前后两个词是完全相关的,出现400次,总共8000词,那么互信息=log((400/8000)/(400/8000)*(400/8000)),约掉之后剩下log(8000/400)。但是一个词如果从头到尾出现了一次,但是并不是单词,则互信息为=log((1/8000)/(1/8000)*(1/8000))=log(8000/1),那么它的互信息会更大。取最少出现次数也会出现问题,就是一些低频率的词不能发现。

我拿了三体去做了新词发现,结果如下:

['丰富', '记录','喜欢','魔鬼','宫殿','告诉我','地摇摇头','专业','苏醒后','油膜','启动了','帮助','悬崖','毕竟是','灵魂','状态下','消失在','曹彬','副舰长','泰勒','概念','汉语','借助','听证会','在周围','三体组织','反物质','怀疑','置身于','清楚地','妈妈','乔纳森','怎么可能','即使在','星环集团','抬头看','咨询','草坪','银河系','美国代表'...]

这里发现‘地摇摇头’、‘置身于’,'毕竟是','状态下'...等变成新词发现出来,类似这些固定搭配的动词性短语确实很难拆开,而且已经识别为二元新词之后,包含该词的二元新词和三元新词是否正确也无法判断,还需要加入一些新的规则继续识别。

代码如下:

from nltk.probability import FreqDist  
f=open(r"C:\Users\user\Documents\Downloads\santi.txt")
text=f.read()

stop_word=['【','】',')','(','、',',','“','”','。','\n','《','》',' ','-','!','?','.','\'','[',']',':','/','.','"','\u3000','’','.',',','…','?']
for i in stop_word:
    text=text.replace(i,"")
    
min_entropy=0.8 
min_p=7
max_gram=4
count_appear=20


def gram(text,max_gram):
    t1=[i for i in text]
    loop=len(t1)+1-max_gram
    t=[]
    for i in range(loop):
        t.append(text[i:i+max_gram])
    if max_gram==1:
        return t1
    else:
        return t
import math
def pro(word):
    len_word=len(word)
    total_count=len(word_all[len_word])
    pro=freq_all[len_word][word]/total_count
    return pro
def entropy(alist):
    f=FreqDist(alist)
    ent=(-1)*sum([i/len(alist)*math.log(i/len(alist)) for i in f.values()])
    return ent

freq_all=[0]
word_all=[0]
for i in range(1,max_gram+1):
    t=gram(text,i)
    freq=FreqDist(t)
    word_all.append(t)
    freq_all.append(freq)
    
#筛选一部分符合互信息的单词
final_word=[]
for i in range(2,max_gram+1):
    for j in word_all[i]:
        if freq_all[i][j]min_p:
               final_word.append(j) 
final_word=list(set(final_word))   
#筛选左右熵
import re
final_word2=[]
for i in final_word:
    lr=re.findall('(.)%s(.)'%i,text)
    left_entropy=entropy([w[0] for w in lr])
    right_entropy=entropy([w[1] for w in lr])
    if min([right_entropy,left_entropy])>min_entropy:
        final_word2.append(i)

去掉常常出现地一些介词和助词,结果如下:

二字词:'曹彬','捕获','恢复','嘿嘿','欺骗','田园','网络','爆炸','杰森','沙漠','胶卷','灵魂','瞄准','宽敞','泡沫','褚岩',...

三字词:国政府','治安军','普通人','绿眼镜','草坪上','常伟思','审问者','大规模','听证会','肥皂泡','猜疑链','PIA','反射镜','追随者','机械臂','大低谷',...

四字词:'球状闪电', '无影无踪', '战略计划', '突然出现', '长长短短', '罗辑博士', '危机纪元', '亚洲舰队', '空灵画师', '曲率引擎', '东方延绪', '同步轨道', '三体问题', '群星计划'...


你可能感兴趣的:(Machine,Learning,自然语言处理)