美文网首页Python数据分析数据挖掘
Numpy计算余弦相似度:向量之间,向量与矩阵,矩阵与矩阵

Numpy计算余弦相似度:向量之间,向量与矩阵,矩阵与矩阵

作者: xiaogp | 来源:发表于2021-03-22 11:40 被阅读0次

    摘要:NumpyPython

    余弦相似度公式

    余弦相似度是衡量向量夹角的余弦值作为相似度度量指标,夹角越小相似度越高

    image.png
    公式为两个向量的点乘除以向量的模长的乘积
    image.png

    计算向量之间余弦相似度

    使用Python的Numpy框架可以直接计算向量的点乘(np.dot),以及向量的模长(np.linalg.norm),余弦相似度在[-1, 1]之间,为了能更直观地和相似度等价,通常转化为[0, 1]之间,如下代码实现计算两个一维向量之间的余弦相似度

    def get_cos_similar(v1: list, v2: list):
        num = float(np.dot(v1, v2))  # 向量点乘
        denom = np.linalg.norm(v1) * np.linalg.norm(v2)  # 求模长的乘积
        return 0.5 + 0.5 * (num / denom) if denom != 0 else 0
    

    计算向量和矩阵的余弦相似度

    如果要计算一个向量和候选所有向量的余弦相似度,使用如下代码将一维向量和多维向量直接点乘

    def get_cos_similar_multi(v1: list, v2: list):
        num = np.dot([v1], np.array(v2).T)  # 向量点乘
        denom = np.linalg.norm(v1) * np.linalg.norm(v2, axis=1)  # 求模长的乘积
        res = num / denom
        res[np.isneginf(res)] = 0
        return 0.5 + 0.5 * res
    

    计算矩阵和矩阵的余弦相似度

    如果要计算两个向量库内,两两向量的余弦相似度,对之前代码稍作修改即可

    def get_cos_similar_matrix(v1, v2):
        num = np.dot(v1, np.array(v2).T)  # 向量点乘
        denom = np.linalg.norm(v1, axis=1).reshape(-1, 1) * np.linalg.norm(v2, axis=1)  # 求模长的乘积
        res = num / denom
        res[np.isneginf(res)] = 0
        return 0.5 + 0.5 * res
    

    效率对比

    先对比计算结果是否一致,没啥问题,三个方法计算的结果一致

    print(get_cos_similar([1, 2, 3], [2, 3, -1]))  # 0.6785714285714286
    print(get_cos_similar([1, 2, 3], [2, -1, -1]))  # 0.3363365823230057
    print(get_cos_similar([2, 5, -1], [2, 3, -1]))  # 0.9879500364742666
    print(get_cos_similar([2, 5, -1], [2, -1, -1]))  # 0.5
    print(get_cos_similar_multi([1, 2, 3], [[2, 3, -1], [2, -1, -1]]))  # [[0.67857143 0.33633658]]
    print(get_cos_similar_matrix([[1, 2, 3], [2, 5, -1]], [[2, 3, -1], [2, -1, -1]]))
    # [[0.67857143 0.33633658]
    #  [0.98795004 0.5       ]]
    

    再对比一下计算一个向量和向量库内其他所有向量的余弦相似度,使用方法一,和使用方法二的效率差异,可以遍历所有向量分别计算一次和直接点乘向量和矩阵效率相差10倍,具体差异需要看向量长度和向量数目

    import time
    v1 = [1, 2, 3, 5, 7, 6, 2, 5, 9, 10]
    v2 = [[2, 5, 1, 8, 4, 1, 1, 3, 1, -5]] * 10000
    t1 = time.time()
    [get_cos_similar(v1, x) for x in v2]
    t2 = time.time()
    print(t2- t1)  # 0.25322484970092773
    t3 = time.time()
    get_cos_similar_multi(v1, v2)
    t4 = time.time()
    print(t4 - t3)  # 0.025495529174804688
    

    最后对比一下两个向量库两两计算余弦相似度分别使用三个方法的效率差异,可见矩阵一次点乘的效率最高,遍历之后多次点乘的效率最低

    v3 = [v1] * 100
    v4 = [[2, 5, 1, 8, 4, 1, 1, 3, 1, -5]] * 100
    t5 = time.time()
    for vv1 in v3:
        for vv2 in v4:
            get_cos_similar(vv1, vv2)
    t6 = time.time()
    print(t6 - t5)  # 0.2532625198364258
    t7 = time.time()
    for vv1 in v3:
        get_cos_similar_multi(vv1, v4)
    t8 = time.time()
    print(t8 - t7)  # 0.03303122520446777
    t9 = time.time()
    get_cos_similar_matrix(v3, v4)
    t10 = time.time()
    print(t10 - t9)  # 0.0014848709106445312
    

    相关文章

      网友评论

        本文标题:Numpy计算余弦相似度:向量之间,向量与矩阵,矩阵与矩阵

        本文链接:https://www.haomeiwen.com/subject/lorzcltx.html