基于哈工大同义词词林的词语间相似度计算

局限:单纯使用同义词词林来计算相似度,如果词典中没有该词,就算不出相似度。

代码(在python3.6上正常运行)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#2018/7/25import mathclass CilinSimilarity(object):"""基于哈工大同义词词林扩展版计算语义相似度"""def __init__(self):"""'code_word' 以编码为key,单词list为value的dict,一个编码有多个单词'word_code' 以单词为key,编码为value的dict,一个单词可能有多个编码'vocab' 所有的单词'N' N为单词总数,包括重复的词"""self.a = 0.65self.b = 0.8self.c = 0.9self.d = 0.96self.e = 0.5self.f = 0.1self.degree = 180self.PI = math.piself.code_word = {}self.word_code = {}self.vocab = set()self.N = 0self.read_cilin()def read_cilin(self):"""读入同义词词林,编码为key,词群为value,保存在self.code_word单词为key,编码为value,保存在self.word_code所有单词保存在self.vocab"""with open('G:/GFZQ/HIT_cilin/cilin_ex.txt', 'r',encoding='UTF-8') as f:for line in f.readlines():res = line.split()code = res[0]words = res[1:]self.vocab.update(words)self.code_word[code] = wordsself.N += len(words)for w in words:if w in self.word_code.keys():self.word_code[w].append(code)else:self.word_code[w] = [code]def similarity(self, w1, w2):"""根据下面这篇论文的方法计算的:基于同义词词林的词语相似度计算方法,田久乐, 赵 蔚(东北师范大学 计算机科学与信息技术学院, 长春 130117 )计算两个单词所有编码组合的相似度,取最大的一个"""# 如果有一个词不在词林中,则相似度为0if w1 not in self.vocab or w2 not in self.vocab:return 0# 获取两个词的编码code1 = self.word_code[w1]code2 = self.word_code[w2]# 最终返回的最大相似度sim_max = 0# 两个词可能对应多个编码for c1 in code1:for c2 in code2:cur_sim = self.sim_by_code(c1, c2)print(c1, c2, '的相似度为:', cur_sim)if cur_sim > sim_max:sim_max = cur_simreturn sim_maxdef sim_by_code(self, c1, c2):"""根据编码计算相似度"""# 先把code的层级信息提取出来clayer1 = self.code_layer(c1)clayer2 = self.code_layer(c2)common_str = self.get_common_str(c1, c2)print('common_str: ', common_str)length = len(common_str)# 如果有一个编码以'@'结尾,那么表示自我封闭,这个编码中只有一个词,直接返回fif c1.endswith('@') or c2.endswith('@') or 0 == length:return self.fcur_sim = 0if 7 <= length:# 如果前面七个字符相同,则第八个字符也相同,要么同为'=',要么同为'#''if c1.endswith('=') and c2.endswith('='):cur_sim = 1elif c1.endswith('#') and c2.endswith('#'):cur_sim = self.eelse:k = self.get_k(clayer1, clayer2)n = self.get_n(common_str)print('k', k)print('n', n)if 1 == length:cur_sim = self.sim_formula(self.a, n, k)elif 2 == length:cur_sim = self.sim_formula(self.b, n, k)elif 4 == length:cur_sim = self.sim_formula(self.c, n, k)elif 5 == length:cur_sim = self.sim_formula(self.d, n, k)return cur_simdef sim_formula(self, coeff, n, k):"""计算相似度的公式,不同的层系数不同"""return coeff * math.cos(n * self.PI / self.degree) * ((n - k + 1) / n)def get_common_str(self, c1, c2):"""获取两个字符的公共部分"""res = ''for i, j in zip(c1, c2):if i == j:res += ielse:breakif 3 == len(res) or 6 == len(res):res = res[0:-1]return resdef get_layer(self, common_str):"""根据common_str返回两个编码所在的层数如果没有共同的str,则位于第一层,0表示第一个字符相同,则位于第二层,1表示这里第一层用0表示"""length = len(common_str)if 1 == length:return 1elif 2 == length:return 2elif 4 == length:return 3elif 5 == length:return 4elif 7 == length:return 5else:return 0def code_layer(sefl, c):"""将编码按层次结构化Aa01A01=第三层和第五层是两个数字表示第一、二、四层分别是一个字母最后一个字符用来去分所有字符相同的情况"""return [c[0], c[1], c[2:4], c[4], c[5:7], c[7]]def get_k(self, c1, c2):"""返回两个编码对应分支的距离,相邻距离为1"""if c1[0] != c2[0]:return abs(ord(c1[0]) - ord(c2[0]))elif c1[1] != c2[1]:return abs(ord(c1[1]) - ord(c2[1]))elif c1[2] != c2[2]:return abs(int(c1[2]) - int(c2[2]))elif c1[3] != c2[3]:return abs(ord(c1[3]) - ord(c2[3]))else:return abs(int(c1[4]) - int(c2[4]))def get_n(self, common_str):"""计算所在分支层的分支数即计算分支的父节点总共有多少个子节点两个编码的common_str决定了它们共同处于哪一层例如,它们的common_str为前两层,则它们共同处于第三层,则我们统计前两层为common_str的第三层编码个数就好了"""if 0 == len(common_str):return 0siblings = set()layer = self.get_layer(common_str)for c in self.code_word.keys():if c.startswith(common_str):clayer = self.code_layer(c)siblings.add(clayer[layer])return len(siblings)def get_code(self, w):"""返回某个单词的编码"""return self.word_code[w]def get_vocab(self):"""返回整个词汇表"""return self.vocab# sim2013 begin =============================def sim2013(self, w1, w2):"""根据下面这篇论文的计算方法:基于词林的词语相似度的度量,吕立辉,梁维薇, 冉蜀阳,(四川大学计算机科学与技术专业)"""# 如果有一个词不在词林中,则相似度为0if w1 not in self.vocab or w2 not in self.vocab:return 0sigma = 0.3codes1 = self.word_code[w1]codes2 = self.word_code[w2]f1 = self.g1(codes1, codes2)f2 = self.g2(codes1, codes2)sim = sigma * f1 + (1 - sigma) * f2return simdef g1(self, codes1, codes2):"""基于词语的路径长度dist(codes1, codes2)计算的相似度这里的dist是取两个单词的最短距离"""alpha = 0.47return self.epow(-alpha * self.dist(codes1, codes2))def g2(self, codes1, codes2):"""考虑密度信息的相似度"""beta = 0.26x = beta * self.dense(codes1, codes2)return (self.epow(x) - self.epow(-1 * x)) / (self.epow(x) + self.epow(-1 * x))def epow(self, x):"""e^x"""return pow(math.e, x)def dist(self, codes1, codes2):"""两个单词的路径距离取最短距离距离其实就等于5减去公共的层次数再乘以2"""dmin = 0for c1 in codes1:for c2 in codes2:common_str = self.get_common_str(c1, c2)layer = self.get_layer(common_str)d = 2 * (5 - layer)if d > dmin:dmin = dreturn dmindef dense(self, codes1, codes2):"""两个单词的密度信息这里的密度信息是两个单词所处分支(包括)之间所有分支含有的单词数。"""dns_max = 0for c1 in codes1:for c2 in codes2:# print(self.N)# print(self.count_word(c1, c2))dns = -1 * math.log(self.count_word(c1, c2) / self.N)  # 默认的log以e为底if dns > dns_max:dns_max = dnsreturn dns_maxdef count_word(self, c1, c2):"""统计两个单词所处分支(包括)之间所有分支含有的单词数。首先,找到所有这样的分支,然后将这些分支含有的单词数相加"""codes = self.codes_between(c1, c2)cnt = 0for code in codes:cnt += len(self.code_word[code])return cntdef codes_between(self, c1, c2):"""获得两个分支之间的所有编码"""codes = set()common_str = self.get_common_str(c1, c2)all_codes = self.code_word.keys()# 如果两个边码相同,则直接返回这个编码if len(common_str) == 8:codes.add(c1)return codesfor c in all_codes:if c.startswith(common_str):layer = self.get_layer(common_str)clayer = self.code_layer(c)if c[layer] <= max(c1[layer], c2[layer]) and c[layer] >= min(c1[layer], c2[layer]):codes.add(c)return codes# sim2013 end =================================# sim2016 begin ===============================def sim2016(self, w1, w2):"""根据以下论文提出的改进方法计算:基于知网与词林的词语语义相似度计算,朱新华,马润聪, 孙 柳,陈宏朝( 广西师范大学 计算机科学与信息工程学院,广西 桂林 541004)"""# 如果有一个词不在词林中,则相似度为0if w1 not in self.vocab or w2 not in self.vocab:return 0sim_max = 0# 获取两个词的编码code1 = self.word_code[w1]code2 = self.word_code[w2]for c1 in code1:for c2 in code2:cur_sim = self.sim2016_by_code(c1, c2)print(c1, c2, cur_sim)if cur_sim > sim_max:sim_max = cur_simreturn sim_maxdef sim2016_by_code(self, c1, c2):"""根据编码计算相似度"""# 先把code的层级信息提取出来clayer1 = self.code_layer(c1)clayer2 = self.code_layer(c2)common_str = self.get_common_str(c1, c2)print('common_str: ', common_str)length = len(common_str)# 如果有一个编码以'@'结尾,那么表示自我封闭,这个编码中只有一个词,直接返回fif c1.endswith('@') or c2.endswith('@') or 0 == length:return self.fcur_sim = 0if 7 <= length:# 如果前面七个字符相同,则第八个字符也相同,要么同为'=',要么同为'#''if c1.endswith('=') and c2.endswith('='):cur_sim = 1elif c1.endswith('#') and c2.endswith('#'):cur_sim = self.eelse:# 从这里开始要改,这之前都一样k = self.get_k(clayer1, clayer2)n = self.get_n(common_str)print('k', k)print('n', n)d = self.dist2016(common_str)print('d', d)e = math.sqrt(self.epow(-1 * k / (2 * n)))print('e', e)cur_sim = (1.05 - 0.05 * d) * ereturn cur_simdef dist2016(self, common_str):"""计算两个编码的距离"""w1 = 0.5w2 = 1w3 = 2.5w4 = 2.5weights = [w1, w2, w3, w4]layer = self.get_layer(common_str)try:if 0 == layer:return 18else:return 2 * sum(weights[0:4 - layer + 1])except Exception as e:print('dist2016 errer, 共有的层数不能大于5')# sim2016 end ====================================if __name__ == '__main__':'''有三种计算方法cs = CilinSimilarity()sim1 = cs.similarity(w1, w2)sim2 = cs.sim2013(w1, w2)sim3 = cs.sim2016(w1, w2)'''cs = CilinSimilarity()w1 = '股票'w2 = '股价'code1 = cs.get_code(w1)print(w1, '的编码有:', code1)code2 = cs.get_code(w2)print(w2, '的编码有:', code2)sim = cs.sim2016(w1, w2)print(w1, w2, '最终的相似度为', sim)

对于词典中没有的词会报错,关于如何扩展词典,后续继续~

代码部分参考:Github

基于同义词词林的词语间相似度计算相关推荐

  1. 同义词词林 java_基于同义词词林扩展版的词语相似度计算

    词语相似度计算 词义相似度计算在很多领域中都有广泛的应用,例如信息检索.信息抽取.文本分类.词义排歧.基于实例的机器翻译等等.国内目前主要是使用知网和同义词词林来进行词语的相似度计算. 本文主要是根据 ...

  2. 词语语义相似度计算简介

    0. 动机 武林高手经常从山川之间顿悟,并由山川之形变化出上乘武艺.风云之间的飘渺互动,实则也为实打实的科学.工程实践提供了指引.风是客观存在的,而只有籍由云,我们才能观察到它.在技术领域的日常工作中 ...

  3. python 语义similarity_GitHub - samelltiger/word_similarity: 基于《知网》的语义相似度计算 python2.7 API...

    基于<知网>的语义相似度计算 python2.7 API 本项目使用python语言实现根据义原树来计算词语之间的语义相似度,并提供对应的 API. 词语距离有两类常见的计算方法,一种是根 ...

  4. 【NLP】基于Word2Vec词向量的中文文本相似度匹配

    Word2Vec 词向量可以用于测量单词之间的相似度,相同语义的单词,其词向量也应该是相似的.对词向量做降维并可视化,可以看到如下图所示的聚类效果,即相近语义的词会聚在一.     文本或句子相似度问 ...

  5. 文本相似度计算(切词、生成词向量,使用余弦相似度计算)

    项目需求 有多个文本,分别是正负样本,使用余弦相似度计算负样本与正样本的样本相似度,若准确率高,后期可判断新加样本与正样本的相似度. 输入如下所示: content label 今天下午,在龙口市诸由 ...

  6. 基于word2vec的疾病和手术相关词语的相似度计算

    项目需要预测是否患有骨质疏松,患者做过的手术类型是其中的一维特征,因此需要得到骨质疏松或骨量减少和手术之间的关系,此处选择用word2vec得到词语之间的相似度. 一.文本预处理 原始数据为csv格式 ...

  7. WMD:基于词向量的文档相似度计算

    EMD算法简介 该部分引用自[1] Earth Mover's Distance (EMD),和欧氏距离一样,他们都是一种距离度量的定义,可以用来测量某分布之间的距离.EMD主要应用在图像处理和语音信 ...

  8. 文本相似度计算 python去停用词_python专业方向 | 文本相似度计算

    欢迎关注我们的微信公众号"人工智能LeadAI"(ID:atleadai)步骤 1.分词.去停用词 2.词袋模型向量化文本 3.TF-IDF模型向量化文本 4.LSI模型向量化文本 ...

  9. 基于Java的文本相似度计算

    目录 1. 前言 1.1 开发环境: 1.2 初步设想 1.3 参考资料 2. HanLP 2.1 在Java中使用HanLP库 2.2 分词函数 3. 双文本对比 3.1 步骤分解 3.2 完整代码 ...

  10. 基于信息内容的词林词语相似度计算 - 论文及代码讲解

    文章目录 论文 同义词林简介 特点 代码 获取词的编码 求IC值 求相似度 选取相似度最大值 论文:<基于信息内容的词林词语相似度计算 >-2018-彭琦,朱新华等 查看 代码:https ...

最新文章

  1. Castle ActiveRecord学习实践(5):实现Many–Many关系的映射
  2. springboot集成swagger2多模块中文配置详细步骤,解决集成mybatis或mybatis-plus无法正常使用问题
  3. Kali Linux安装字典StarDict
  4. JAVA中return与finally的先后关系
  5. weka: FCBFSearch
  6. 又有一本图书在台湾出版了
  7. python3:语法变动 及新特性
  8. Shell Perl Python 介绍
  9. Windows下安装pip
  10. linux 核显驱动程序,在Ubuntu系统上安装英特尔核显驱动安装器的方法
  11. 移动应用开发--实现QQ登录界面(Android)
  12. SSL-ZYC 2133 腾讯大战360
  13. string的取值范围
  14. 关于疫情,你想到什么?
  15. 微信小程序地图篇(腾讯地图)
  16. 成都启英泰伦科技有限公司
  17. AKM AKM-35-4-01-15X-10
  18. 怎么给自己的电脑连接打印机
  19. 通过命令行玩转Git,需要记住那些命令?
  20. win10不能访问samba共享问题的解决

热门文章

  1. Spring AOP动态代理的实现方式
  2. ImageJ的自动二值算法C++实现
  3. FCM算法的matlab程序
  4. 三大知名PHP开源多用户商城系统对比
  5. 基于Java+SpringBoot+vue+elementui图书商城系统设计实现
  6. 多路数据采集系统软件测试,基于AT89S52多路数据采集系统的设计-测试测量-与非网...
  7. 差分管电路图_差分放大器的非线性应用
  8. 实现 8086 汇编编译器(一)——基本框架
  9. 百度影音盒插入论坛帖子自动播放代码及方法
  10. PCB电路板生产完成分析