在nlp任务中,经常会遇到求解相似语句判断的场景,这就涉及到了句子的相似性判断。目前常用的两种方法是基于word-level级别和sentence-level级别。
一、Word-level的思想是通过对句子进行分词,分别计算两个比较句子中所含词汇的相似度。主要包含两个核心问题,一个是词的相似度计算问题,另一个是对多个词进行相似度加权融合问题
1.1 基于word的相似度计算问题
目前重用的方法是基于语义知识库进行词的相似度计算,比如hownet和哈工大研发的词林。可以在一定程度上解决问题,但知识库的词汇有限,难以大规模使用。
1.2 基于word相似度的句子加权融合问题
这里主要涉及词相似的句子相似度度量的问题,常用的方法是jaccard编辑距离和语义距离
定义如下:
Word1 = [token for token in s1]
Word2 = [token for token in s2]
Jaccard距离
SIM(s1,s2) = intersection(word1,word2)/union(word1,word2)
语义距离
SIM(s1,s2) = 1/2*(sum(max(sim(word1,word2)for wrd1 in words1 for word2 in words2))/len(words1)+ sum(max(sim(word2,word1)for word2 in words2 for word1 in words2))/len(words2))
二、Sentence-level是采用句子建模的方法,核心思想是利用向量空间模型,将句子进行向量表征,通常有两种方式,基于word-vector的组合以及sentence-vector
2.1 基于word-vector的组合
目前常用的是使用预先训练好的word-embedding向量,对于一个句子,将词向量的每一位进行求和或者平均。另一种是使用one-hot结合的tfidf对句子进行vsm表示。
2.2 基于sentence-vector的方法
目前关于sentence建模的方法包括skip-gram,cbow的doc2vec建模方法,基于autoencoder建模、基于skip-thought的句子建模方法。基于sentence-vector的方法能够更好的保留句子语义信息,这是词袋所不能达到的。
本文主要提供两种相似性的计算方法,一种是基于simhash算法计算相似度(没有考虑语义),另一种是基于词向量计算其相似性
代码如下:
# 基于simhash算法进行句子相似度的计算 from simhash import Simhash import jieba.posseg as poseg def haming_distanc(code_s1,code_s2): # 利用64位数,计算海明距离 x = (code_s1^code_s2)&((1<<64)-1) ans = 0 while x: ans +=1 x &=x-1 return ans def get_features(string): word_list = [word.word for word in poseg.cut(string) if word.flag[0] not in ['u','x','w','o','p','c','m','q']] return word_list # 计算两个全文编码距离 def get_distance(code_s1,code_s2): return haming_distanc(code_s1,code_s2) # 对全文进行编码 def get_code(string): return Simhash(get_features(string)).value def distance(s1,s2): code_s1 = get_code(s1) code_s2 = get_code(s2) similarity = (100 - haming_distanc(code_s1,code_s2)*100/64)/100# 总共是利用的64位数 return similarity s1 ="我喜欢你" s2 = "你非常的喜欢我"
# 基于词向量的句子相似性 import gensim import numpy as np import jieba.posseg as pesg embedding_path = "D:\workspace\project\\NLPcase\\sentenceSimilarity\\data\\word_vector.bin" model = gensim.models.KeyedVectors.load_word2vec_format(embedding_path,binary=False) # 获取词向量 def get_wordvector(word): try: return model[word] except: return np.zeros(200) # 基于余弦相似度计算句子之间的相似度,句子向量求平均 def similarity_cosin(word_list1,word_list2): vector1 = np.zeros(200) for word in word_list1: vector1+=get_wordvector(word) vector1 = vector1/len(word_list1) vector2 = np.zeros(200) for word in word_list2: vector2 += get_wordvector(word) vector2 = vector2 / len(word_list2) cos1 = np.sum(vector1*vector2) cos21 = np.sqrt(sum(vector1 ** 2)) cos22 = np.sqrt(sum(vector2 ** 2)) similarity = cos1 / float(cos21 * cos22) return similarity '''计算句子相似度''' def distance(text1, text2): word_list1=[word.word for word in pesg.cut(text1) if word.flag[0] not in ['w','x','u']] word_list2=[word.word for word in pesg.cut(text2) if word.flag[0] not in ['w','x','u']] return similarity_cosin(word_list1,word_list2)
总结
主要用于学习笔记的使用,句子向量的模型的训练可以借鉴于word2vec的方法。
参考文献
https://cloud.tencent.com/developer/article/1145941
https://www.cnblogs.com/llhthinker/p/10335164.html
https://github.com/liuhuanyong/SentenceSimilarity
https://www.cnblogs.com/arachis/p/Similarity.html