在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的方法。