语义计算索引作业一 词义相似度计算
实现2种词汇相关度计算方法,基于词典与基于语料各一种
基于Mturk-771进行实验和分析(开放式) : http://www2.mta.ac.il/~gideon/mturk771.html
基于词典的方式:
这里我们使用WordNet词典,使用的工具是nltk,利用里面自带的相似度方法来计算词义相似度。Nltk是比较知名的Python自然语言处理包,从里面可以导入wordnet词典和一些语料,来帮助我们进行词义等的分析。其中有六种相似度计算的算法:
brown_ic = wordnet_ic.ic('ic-brown.dat')
path_similarity(c1,c2) # 词在词典层次结构中的最短路径
wup_similarity(c1,c2) # Wu-Palmer 提出的最短路径
lch_similarity(c1,c2) # Leacock Chodorow 最短路径加上类别信息
res_similarity(c1,c2, brown_ic) # -log P(LCS(c1,c2)) 公共包容节点在层次结构中位置越低,相似性越大
jcn_similarity(c1,c2, brown_ic) # 1/2 * log P(LCS(c1,c2)) - (logP(c1) + logP(c2))
lin_similarity(c1,c2, semcor_ic) # 2 * log P(LCS(c1,c2)) / (logP(c1) + logP(c2))

特殊处理:
1、 其中lin_similarity、wup_similarity和path_similarity结果范围在[0,1]之间,而由我们的数据可知,数据结果应该在[0,5]之间,因此这里我们把结果×5进行处理。
2、 一个词会有多种词义,判断两个词需要让两个词之间的各个词义进行比较。如何判断两个词之间的相似度呢?我同时使用了最大值和平均值,发现平均值得到的结果会非常小,猜想两个词之间可能有较多的词义无关,影响了结果,因此最后选择用最大值。
3、 lch_similarity得到的值都不大,因此最后进行了归一化处理×5
4、 res_similarity(c1,c2, brown_ic) jcn_similarity(c1,c2, brown_ic)得到的结果存在le+300,而第二大的数分别为12.26837533572617和19.273454235478546,因此取13和20代替原来的最大le+300。
def getsim(s1,s2):
# semcor_ic = wordnet_ic.ic('ic-semcor.dat')#
# s1=wn.synset('assembly.n.01')
path = 0.0
lin = 0.0
lch = 0.0
wup = 0.0
res = 0.0
jcn = 0.0
x1 = wn.synsets(s1)
x2 = wn.synsets(s2)
# s2=wn.synset('crowd.n.01')
# print(s1.path_similarity(s2))
# wordnet_ic Information Content: Load an information content file from the wordnet_ic corpus.
for i in range(len(x1)):
for j in range(len(x2)):
try:
res1 = x1[i].res_similarity(x2[j], brown_ic)
except:
res1 = 0.0
try:
lin1 = x1[i].lin_similarity(x2[j], brown_ic)
except:
lin1 = 0.0
path1 = x1[i].path_similarity(x2[j])
try:
lch1 = x1[i].lch_similarity(x2[j])
except:
lch1 = 0.0
wup1 = x1[i].wup_similarity(x2[j])
try:
jcn1 = x1[i].jcn_similarity(x2[j], brown_ic)
except:
jcn1 = 0.0
if res1 and res1 > res:
if res1==1e+300:
res=13
else:
res = res1
if lin1 and lin1 > lin:
lin = lin1
if path1 and path1 > path:
path = path1
if lch1 and lch1 > lch:
lch = lch1
if wup1 and wup1 > wup:
wup = wup1
if jcn1 and jcn1 > jcn:
if jcn1==1e+300:
jcn = 20
else:
jcn=jcn1
return res,lin*5,lch,jcn,wup*5,path*5#×5是为了得到五分分值
剩余分数则是归一化后再×5
五分分值:

基于语料的方法
因为预训练词向量都比较大,这里就使用了gensim中的word2vec模型进行自行训练,训练语料为text8,大概有100M左右。
trains=word2vec.Text8Corpus("text8")
model = word2vec.Word2Vec(trains,size=100,min_count=1,window=5,iter=10)
model.save(u'text2vec.model')
最后得到的结果如下图:score为真实评分分布,w2v为word2vec实际评分分布。

结果比较与分析
结果分析使用了均方误差

由图可以看出,word2vec方法和 res算法结果较好,观察预测结果分布,可以看出这两种方法和真实结果分布比较相似。
在观察时,我们也发现,path等方法相似度偏向与1(或者是5)左右,原因是我们这里取的是最大值,对于account,explanation这两个单词,因为它们有相同的词义,这里就认为相似度最大。但实际在现实生活中,考虑两个词词义是否相似,除却词义的重合程度外,可能还要考虑两个词是否是常用词义相似等等。比如两个词常用含义相似和两个词罕见含义相似,虽然都是某种词义相似,但显然前者更能体现词的相似度。
因此可能取平均和取最大都不能很好的描述两个词之间的相似度。而语料的方法则可以得到词的常用和罕见意义这一信息。这里用word2vec训练语料有限,可能结果也不是非常准确,相信如果网上很多预训练的词向量可能会有更好的结果。
网友评论