我想计算两个列表之间的余弦相似度,比如说,列表1是dataSetI,列表2是dataSetII。

假设dataSetI是[3,45,7,2],dataSetII是[2,54,13,15]。列表的长度总是相等的。我想将余弦相似度报告为0到1之间的数。

dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]

def cosine_similarity(list1, list2):
  # How to?
  pass

print(cosine_similarity(dataSetI, dataSetII))

当前回答

如果你碰巧已经在使用PyTorch,你应该使用他们的cosessimilarity实现。

假设有两个n维的numpy。ndarray, v1和v2,即它们的形状都是(n,)。以下是如何获得它们的余弦相似度:

import torch
import torch.nn as nn

cos = nn.CosineSimilarity()
cos(torch.tensor([v1]), torch.tensor([v2])).item()

或者假设有两个numpy。ndarray w1和w2,它们的形状都是(m, n)。下面给你一个余弦相似度列表,每个都是w1中的一行和w2中的相应行之间的余弦相似度:

cos(torch.tensor(w1), torch.tensor(w2)).tolist()

其他回答

所有答案都非常适合不能使用NumPy的情况。如果可以的话,这里有另一种方法:

def cosine(x, y):
    dot_products = np.dot(x, y.T)
    norm_products = np.linalg.norm(x) * np.linalg.norm(y)
    return dot_products / (norm_products + EPSILON)

还要记住EPSILON = 1e-07,以确保组织安全。

你可以使用sklearn.metrics.pairwise docs中的cosine_similarity函数

In [23]: from sklearn.metrics.pairwise import cosine_similarity

In [24]: cosine_similarity([[1, 0, -1]], [[-1,-1, 0]])
Out[24]: array([[-0.5]])

Python代码计算:

余弦距离 余弦相似度 角距离 角相似


import math

from scipy import spatial


def calculate_cosine_distance(a, b):
    cosine_distance = float(spatial.distance.cosine(a, b))
    return cosine_distance


def calculate_cosine_similarity(a, b):
    cosine_similarity = 1 - calculate_cosine_distance(a, b)
    return cosine_similarity


def calculate_angular_distance(a, b):
    cosine_similarity = calculate_cosine_similarity(a, b)
    angular_distance = math.acos(cosine_similarity) / math.pi
    return angular_distance


def calculate_angular_similarity(a, b):
    angular_similarity = 1 - calculate_angular_distance(a, b)
    return angular_similarity

相似性搜索:

如果你想在嵌入数组中找到最接近的余弦相似度,你可以使用Tensorflow,就像下面的代码。

在我的测试中,在不到一秒钟(使用GPU)的时间内,在1M嵌入(1' 000,000 '000 x512)中找到形状为1x512的嵌入的最接近值。

import time

import numpy as np  # np.__version__ == '1.23.5'
import tensorflow as tf  # tf.__version__ == '2.11.0'

EMBEDDINGS_LENGTH = 512
NUMBER_OF_EMBEDDINGS = 1000 * 1000


def calculate_cosine_similarities(x, embeddings):
    cosine_similarities = -1 * tf.keras.losses.cosine_similarity(x, embeddings)
    return cosine_similarities.numpy()


def find_closest_embeddings(x, embeddings, top_k=1):
    cosine_similarities = calculate_cosine_similarities(x, embeddings)
    values, indices = tf.math.top_k(cosine_similarities, k=top_k)
    return values.numpy(), indices.numpy()


def main():
    # x shape: (512)
    # Embeddings shape: (1000000, 512)
    x = np.random.rand(EMBEDDINGS_LENGTH).astype(np.float32)
    embeddings = np.random.rand(NUMBER_OF_EMBEDDINGS, EMBEDDINGS_LENGTH).astype(np.float32)

    print('Embeddings shape: ', embeddings.shape)

    n = 100
    sum_duration = 0
    for i in range(n):
        start = time.time()
        best_values, best_indices = find_closest_embeddings(x, embeddings, top_k=1)
        end = time.time()

        duration = end - start
        sum_duration += duration

        print('Duration (seconds): {}, Best value: {}, Best index: {}'.format(duration, best_values[0], best_indices[0]))

    # Average duration (seconds): 1.707 for Intel(R) Core(TM) i7-10700 CPU @ 2.90GHz
    # Average duration (seconds): 0.961 for NVIDIA 1080 ti
    print('Average duration (seconds): ', sum_duration / n)


if __name__ == '__main__':
    main()

对于更高级的相似度搜索,你可以使用Milvus, Weaviate或Faiss。


https://en.wikipedia.org/wiki/Cosine_similarity https://gist.github.com/amir-saniyan/e102de09b01c4ed1632e3d1a1a1cbf64

import math
from itertools import izip

def dot_product(v1, v2):
    return sum(map(lambda x: x[0] * x[1], izip(v1, v2)))

def cosine_measure(v1, v2):
    prod = dot_product(v1, v2)
    len1 = math.sqrt(dot_product(v1, v1))
    len2 = math.sqrt(dot_product(v2, v2))
    return prod / (len1 * len2)

你可以在计算后四舍五入:

cosine = format(round(cosine_measure(v1, v2), 3))

如果你想让它真的很短,你可以使用下面的一行代码:

from math import sqrt
from itertools import izip

def cosine_measure(v1, v2):
    return (lambda (x, y, z): x / sqrt(y * z))(reduce(lambda x, y: (x[0] + y[0] * y[1], x[1] + y[0]**2, x[2] + y[1]**2), izip(v1, v2), (0, 0, 0)))

我们可以用简单的数学公式计算余弦相似度。 Cosine_similarity = 1-(向量的点积/向量范数的积)。我们可以定义两个函数分别用于点积和范数的计算。

def dprod(a,b):
    sum=0
    for i in range(len(a)):
        sum+=a[i]*b[i]
    return sum

def norm(a):

    norm=0
    for i in range(len(a)):
    norm+=a[i]**2
    return norm**0.5

    cosine_a_b = 1-(dprod(a,b)/(norm(a)*norm(b)))