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