Advertisement

『NLP学习笔记』向量与矩阵、矩阵与矩阵的余弦相似度

阅读量:

本文介绍了余弦相似度的基本概念及其计算方法,并详细讨论了不同情况下(如向量与向量、向量与矩阵、矩阵与矩阵)的余弦相似度计算方式及Python实现。具体包括:
余弦相似度定义:利用两个向量夹角的余弦值衡量个体差异,值越接近1表示越相似。
公式推导:提供了两向量间的余弦相似性公式,并通过例子说明其应用。
Python实现:

  • 向量与向量:使用numpy库计算点积和范数。
  • 向量与矩阵:通过将矩阵每一行视为向量进行计算。
  • 矩阵间:采用点积和范数计算每对行之间的相似性。
    加速技巧:探讨了在高维数据中的优化方法。
    sklearn应用:展示了如何利用sklearn库中的函数快速计算余弦相似性。
    摘要覆盖了理论基础、具体算法及实际应用案例,适合需要了解或实施余弦相似度计算的读者。
向量与矩阵、矩阵与矩阵的余弦相似度

文章目录

3.2

  • 四. 参考文献

一. 余弦相似度计算

  • 余弦相似度 用向量空间中两个向量夹角的余弦值作为衡量两个个体间差异的大小。余弦值越接近1,就表明夹角越接近0度,也就是两个向量越相似,这就叫"余弦相似性"。
  • 我们知道,对于两个向量,如果他们之间的夹角越小,那么我们认为这两个向量是越相似的。余弦相似性就是利用了这个理论思想。它通过计算两个向量的夹角的余弦值来衡量向量之间的相似度值。余弦相似性推导公式如下:

\begin{aligned} &\cos (\theta)=\frac{\mathbf{a} \bullet \mathbf{b}}{|| \mathbf{a}|| \times|| \mathbf{b}||} \\ &=\frac{\left(x_{1}, y_{1}\right) \bullet\left(x_{2}, y_{2}\right)}{\sqrt{x_{1}^{2}+y_{1}^{2}} \times \sqrt{x_{2}^{2}+y_{2}^{2}}} \\ &=\frac{x_{1} x_{2}+y_{1} y_{2}}{\sqrt{x_{1}^{2}+y_{1}^{2}} \times \sqrt{x_{2}^{2}+y_{2}^{2}}}\tag{1} \end{aligned}

下面举一个例子用于说明余弦计算文本相似度

复制代码
    # !/usr/bin/env python
    # -*- encoding: utf-8 -*-
    import re
    import copy
    import jieba
    from collections import Counter
    
    import numpy as np
    
    p = re.compile(r'[\u4e00-\u9fa5]+')
    
    sentence1 = "这只皮靴号码大了。那只号码合适!"
    sentence2 = "这只皮靴号码不小,那只更合适!"
    
    sent1 = "".join(p.findall(sentence1))
    sent2 = "".join(p.findall(sentence2))
    print(sent1)
    print(sent2)
    
    res1 = jieba.lcut(sent1)
    print(res1)
    res2 = jieba.lcut(sent2)
    print(res2)
    
    all_ci = copy.deepcopy(res1)
    for one in res2:
    if one not in res1:
        all_ci.append(one)
    print(all_ci)
    
    dict_sent1 = Counter(res1)
    dict_sent2 = Counter(res2)
    
    # 向量1
    vector1 = np.zeros(len(all_ci))
    vector2 = np.zeros(len(all_ci))
    for idx, one in enumerate(res1):
    vector1[idx] = dict_sent1[one]
    for idx, one in enumerate(res2):
    vector2[idx] = dict_sent2[one]
    print(vector1)
    print(vector2)
    
    
    def vector_vector(a, b):
    """ 向量与向量之间的余弦相似性 """
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
    
    
    print("两个句子的相似性:", vector_vector(vector1, vector2))
复制代码
    ['这', '只', '皮靴', '号码', '大', '了', '那', '只', '号码', '合适']
    ['这', '只', '皮靴', '号码', '不小', '那', '只', '更', '合适']
    ['这', '只', '皮靴', '号码', '大', '了', '那', '只', '号码', '合适', '不小', '更']
    [1. 2. 1. 2. 1. 1. 1. 2. 2. 1. 0. 0.]
    [1. 2. 1. 1. 1. 1. 2. 1. 1. 0. 0. 0.]
    两个句子的相似性: 0.8807710121010883

二. 向量与矩阵、矩阵与矩阵的余弦相似度

其实这个过程非常简单:套用该方法时只需要将以下公式代入即可。
\frac{\sum_{i=1}^{n} \mathbf A_{i} \times \mathbf B_{i}}{\sqrt{\sum_{i=1}^{n}\left(\mathbf A_{i}\right)^{2}} \times \sqrt{\sum_{i=1}^{n}\left(\mathbf B_{i}\right)^{2}}}

三. Python具体实现

3.1. 向量与向量

  • 向量与向量的余弦相似性:
复制代码
    import numpy as np
    
    a = np.array([1, 2, 1, 2, 3, 5, 6, 2])
    b = np.array([1, 2, 1, 4, 6, 5, 5, 2])
    print(a.shape, b.shape)
    
    def vector_vector(a, b):
    """ 向量与向量之间的余弦相似性 """
    return np.dot(a, b) / (np.linalg.norm(a)*np.linalg.norm(b))
    
    vector_vector(a, b)
复制代码
    (8,) (8,)
    0.9381941874331419

3.2. 向量与矩阵

  • 向量与矩阵的余弦相似性:
复制代码
    import numpy as np
    
    a = np.array([1, 2, 1, 2, 3, 5, 6, 2])
    B = np.array([
    [1, 2, 1, 2, 3, 5, 6, 2],
    [1, 2, 1, 2, 3, 5, 6, 2],
    [2, 3, 3, 2, 1, 2, 1, 1],
    [2, 2, 1, 1, 1, 2, 4, 4]
    ])
    print(a.shape, B.shape)
    
    
    def vector_matrix(a, B):
    """ 向量与矩阵之间的余弦相似性 """
    return np.dot(B, a) / (np.linalg.norm(a) * np.linalg.norm(B, axis=1))
    
    print(vector_matrix(a, B))
复制代码
    (8,) (4, 8)
    [1.         1.         0.68376346 0.85941947]

3.3. 矩阵与矩阵

  • 矩阵与矩阵的余弦相似性:
复制代码
    import numpy as np
    
    B = np.array([
    [1, 2, 1, 2, 3, 5, 6, 2],
    [1, 2, 1, 2, 3, 5, 6, 2],
    [2, 3, 3, 2, 1, 2, 1, 1],
    [2, 2, 1, 1, 1, 2, 4, 4]
    ])
    
    C = np.array([
    [1, 2, 1, 2, 3, 5, 6, 2],
    [2, 1, 1, 2, 1, 2, 3, 3],
    [2, 3, 3, 2, 1, 2, 1, 1],
    [2, 2, 1, 1, 1, 2, 4, 4]
    ])
    
    def matrix_matrix(A, B):
    """ 矩阵与矩阵之间的余弦相似性 """
    return  np.dot(A, B.T).diagonal() / (np.linalg.norm(A, axis=1) * np.linalg.norm(B, axis=1))
    
    matrix_matrix(B, C)
复制代码
    [1.         0.87369775 1.         1.        ]

3.4. 人脸识别中的加速技巧

复制代码
    import numpy as np
    import time
    
    
    # 当前检测到的人脸特征128维度
    face_feat = np.random.random((128, ))
    
    # 人脸底库特征
    face_db = np.random.random((100000, 128))
    
    
    def vector_matrix(a, B):
    """ 向量与矩阵之间的余弦相似性 """
    return np.dot(B, a) / (np.linalg.norm(a) * np.linalg.norm(B, axis=1))
    
    start1 = time.time()
    for i in range(100):
    sim = vector_matrix(face_feat, face_db)
    print("直接计算相似性耗时:", time.time()-start1)
    
    # 直接计算相似性耗时: 22.094916105270386
复制代码
    def vector_matrix_T(a, B, B_l2):
    """ 向量与矩阵之间的余弦相似性 """
    return np.dot(B, a) / (np.linalg.norm(a) * B_l2)
    
    
    face_db_l2 = np.linalg.norm(face_db, axis=1)
    start1 = time.time()
    for i in range(100):
    sim = vector_matrix_T(face_feat, face_db, face_db_l2)
    print("先计算L2,再计算相似度耗时:", time.time()-start1)
    
    # 先计算L2,再计算相似度耗时: 0.625633955001831

3.5. sklearn包求余弦相似性

复制代码
    import numpy as np
    from sklearn.metrics.pairwise import cosine_similarity
    
    a1 = np.arange(15).reshape(3, 5)
    a2 = np.arange(20).reshape(4, 5)
    cosine_similarity(a1, a2) #第一行的值是a1中的第一个行向量与a2中所有的行向量之间的余弦相似度
    # array([[1.        , 0.91465912, 0.87845859, 0.86154979],
    #       [0.91465912, 1.        , 0.99663684, 0.99323905],
    #       [0.87845859, 0.99663684, 1.        , 0.9994114 ]])
    
    cosine_similarity(a1)   #a1中的行向量之间的两两余弦相似度
    # array([[1.        , 0.91465912, 0.87845859],
    #       [0.91465912, 1.        , 0.99663684],
    #       [0.87845859, 0.99663684, 1.        ]])

四. 参考文献

  1. 计算余弦相似度:在https://www.cnblogs.com/dsgcBlogs/p/8619566.html中详细介绍了如何计算余弦相似度。
    2. 向量与矩阵之间的余弦相似度:参考
    3. Python库sklearn进行余弦相似度计算:本文详细讲解了如何利用Python库sklearn来实现余弦相似度的计算。

全部评论 (0)

还没有任何评论哟~