nlp自然语言处理中句子相似度计算

在做自然语言处理的过程中,现在智能对话比较火,例如智能客服,智能家电,智能音箱等,我们需要获取用户说话的意图,方便做出正确的回答,这里面就涉及到句子相似度计算的问题,那么本节就来了解一下怎么样来用 Python 实现句子相似度的计算。

句子相似度常用的几种方法:
1、编辑距离
2、杰卡德系数计算
3、Word2Vec 计算

编辑距离,英文叫做 Edit Distance,又称 Levenshtein 距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数,
如果它们的距离越大,说明它们越是不同。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

例如我们有两个字符串:string 和 setting,如果我们想要把 string 转化为 setting,需要这么两步:

第一步,在 s 和 t 之间加入字符 e。
第二步,把 r 替换成 t。
所以它们的编辑距离差就是 2,这就对应着二者要进行转化所要改变(添加、替换、删除)的最小步数。

安装:pip3 install distance

import distance

str1 = "公司地址是哪里"
str2 = "公司在什么位置"

def edit_distance(s1, s2):
    return distance.levenshtein(s1, s2)

print(edit_distance(str1, str2))

想要获取相似的文本的话可以直接设定一个编辑距离的阈值来实现,如设置编辑距离为 2

def edit_distance(s1, s2):
    return distance.levenshtein(s1, s2)

strings = [
    '你在干什么',
    '你在干啥子',
    '你在做什么',
    '你好啊',
    '我喜欢吃香蕉'
]

target = '你在干啥'
results = list(filter(lambda x: edit_distance(x, target) <= 2, strings))
print(results)
# ['你在干什么', '你在干啥子']

杰卡德系数计算

杰卡德系数,英文叫做 Jaccard index, 又称为 Jaccard 相似系数,用于比较有限样本集之间的相似性与差异性。Jaccard 系数值越大,样本相似度越高。

实际上它的计算方式非常简单,就是两个样本的交集除以并集得到的数值,当两个样本完全一致时,结果为 1,当两个样本完全不同时,结果为 0。

算法非常简单,就是交集除以并集,下面我们用 Python 代码来实现一下:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np

def jaccard_similarity(s1, s2):
    def add_space(s):
        return ' '.join(list(s))

    # 将字中间加入空格
    s1, s2 = add_space(s1), add_space(s2)
    # 转化为TF矩阵
    cv = CountVectorizer(tokenizer=lambda s: s.split())
    corpus = [s1, s2]
    vectors = cv.fit_transform(corpus).toarray()
    # 获取词表内容
    ret = cv.get_feature_names()
    print(ret)
    # 求交集
    numerator = np.sum(np.min(vectors, axis=0))
    # 求并集
    denominator = np.sum(np.max(vectors, axis=0))
    # 计算杰卡德系数
    return 1.0 * numerator / denominator


s1 = '你在干嘛呢'
s2 = '你在干什么呢'
print(jaccard_similarity(s1, s2))

Word2Vec,顾名思义,其实就是将每一个词转换为向量的过程。如果不了解的话可以参考:https://blog.csdn.net/itplus/article/details/37969519

Word2Vec的词向量模型是训练的维基百科的中文语库,这里模型有250维和50维,向量维度越大模型越大,计算越复杂,正常使用时,需要小的模型,发现50维的也差不多,训练模型方式和模型下载请参考:之前文章。
流程:
01、对句子进行拆词
02、去除无用的分词
03、计算句子平均词向量
04、余弦相似度

对句子进行拆词:Python提供了很对可用库,自行选择
去除无用的分词:删除没用的语气词等,为的是减少对计算句子平均词向量的影响。
计算句子平均词向量用的是AVG-W2V,计算句子平均词向量,所以02步尤为重要
余弦相似度:

余弦相似度 np.linalg.norm(求范数)(向量的第二范数为传统意义上的向量长度
dist1=float(np.dot(vec1,vec2)/(np.linalg.norm(vec1)*np.linalg.norm(vec2)))
def key_words_ask_method(sentence1, sentence2):
    '''
    因为无论是#1:AVG-W2V 2:AVG-W2V-TFIDF 都需要求得平均值,
    除数:决定整个数据的大小  被除数:影响平均值
    所以 分词的标准很重要,可通过自定义词典、停用词 和 语义分析进行适当处理
    '''
    vec1 = sentence_to_vec(sentence1)
    vec2 = sentence_to_vec(sentence2)

    # 零向量直接返回
    if (vec1 == np.zeros(WORD_VECTOR_DIM)).all() == True or (vec2 == np.zeros(WORD_VECTOR_DIM)).all() == True:
        return "不符合相似"

    # score = cos(vec1, vec2)
    # print(score)
    # if score < COSINE_CRITICAL_VALUE:
    #     return "1"
    # else:
    #     return "0"

    # 余弦相似度 np.linalg.norm(求范数)(向量的第二范数为传统意义上的向量长度
    dist1=float(np.dot(vec1,vec2)/(np.linalg.norm(vec1)*np.linalg.norm(vec2)))
    print("score:", dist1)
    if dist1 > 0.92:
        return "两个句子相似"
    else:
        return "两个句子不相似"
 
image.png



posted @ 2020-02-15 10:43  Raymone1125  阅读(984)  评论(0编辑  收藏  举报