zoukankan      html  css  js  c++  java
  • 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



  • 相关阅读:
    Java代码实现依赖注入
    Linux shell脚本的字符串截取
    Android教程:wifi热点问题
    Android framework层实现实现wifi无缝切换AP
    http mimetype为multipart/x-mixed-replace报文
    Realtek 8192cu 支持 Android Hotspot 软ap
    http协议详解
    Android 在一个程序中启动另一个程序(包名,或者类名)
    linux定时器
    进程与线程的一个简单解释(转)
  • 原文地址:https://www.cnblogs.com/klausage/p/12310844.html
Copyright © 2011-2022 走看看