推荐: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','反射镜','追随者','机械臂','大低谷',...
四字词:'球状闪电', '无影无踪', '战略计划', '突然出现', '长长短短', '罗辑博士', '危机纪元', '亚洲舰队', '空灵画师', '曲率引擎', '东方延绪', '同步轨道', '三体问题', '群星计划'...