我需要计算两个列表之间的余弦相似度,例如,列表1是dataSetI
,列表2是{{1} }。我不能使用诸如 numpy 或统计模块之类的东西。我必须使用通用模块(数学等)(以及尽可能少的模块,以减少花费的时间)。
假设dataSetII
为dataSetI
而[3, 45, 7, 2]
为dataSetII
。列表的长度总是相等。
当然,余弦相似度在 0和1 之间,并且为了它,它将用[2, 54, 13, 15]
四舍五入到第三或第四位小数。
非常感谢您提前帮助。
答案 0 :(得分:121)
您应该尝试SciPy。它有一堆有用的科学例程,例如“用数字计算积分,求解微分方程,优化和稀疏矩阵的例程”。它使用超高速优化的NumPy进行数字运算。有关安装,请参阅here。
请注意,spatial.distance.cosine计算距离,而不是相似度。因此,您必须从1中减去该值才能获得相似性。
from scipy import spatial
dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]
result = 1 - spatial.distance.cosine(dataSetI, dataSetII)
答案 1 :(得分:50)
您可以使用cosine_similarity
功能表单sklearn.metrics.pairwise
docs
In [23]: from sklearn.metrics.pairwise import cosine_similarity
In [24]: cosine_similarity([1, 0, -1], [-1,-1, 0])
Out[24]: array([[-0.5]])
答案 2 :(得分:50)
另一个版本仅基于numpy
from numpy import dot
from numpy.linalg import norm
cos_sim = dot(a, b)/(norm(a)*norm(b))
答案 3 :(得分:30)
我认为这里的表现并不重要,但我无法抗拒。 zip()函数完全重新复制两个向量(实际上更多的是矩阵转置),只是为了获得“Pythonic”顺序的数据。为实施细节和实施计划会很有趣:
import math
def cosine_similarity(v1,v2):
"compute cosine similarity of v1 to v2: (v1 dot v2)/{||v1||*||v2||)"
sumxx, sumxy, sumyy = 0, 0, 0
for i in range(len(v1)):
x = v1[i]; y = v2[i]
sumxx += x*x
sumyy += y*y
sumxy += x*y
return sumxy/math.sqrt(sumxx*sumyy)
v1,v2 = [3, 45, 7, 2], [2, 54, 13, 15]
print(v1, v2, cosine_similarity(v1,v2))
Output: [3, 45, 7, 2] [2, 54, 13, 15] 0.972284251712
通过一次一个地提取元素的C类噪声,但没有批量数组复制,并且在单个for循环中完成所有重要操作,并使用单个平方根。
ETA:更新了打印调用功能。 (原始版本是Python 2.7,而不是3.3。当前在Python 2.7下使用from __future__ import print_function
语句运行。)无论哪种方式,输出都是相同的。
3.0GHz Core 2 Duo上的CPYthon 2.7.3:
>>> timeit.timeit("cosine_similarity(v1,v2)",setup="from __main__ import cosine_similarity, v1, v2")
2.4261788514654654
>>> timeit.timeit("cosine_measure(v1,v2)",setup="from __main__ import cosine_measure, v1, v2")
8.794677709375264
因此,在这种情况下,unpythonic方式快了大约3.6倍。
答案 4 :(得分:12)
我根据问题中的几个答案做了benchmark,以下片段被认为是最佳选择:
def dot_product2(v1, v2):
return sum(map(operator.mul, v1, v2))
def vector_cos5(v1, v2):
prod = dot_product2(v1, v2)
len1 = math.sqrt(dot_product2(v1, v1))
len2 = math.sqrt(dot_product2(v2, v2))
return prod / (len1 * len2)
结果让我感到惊讶的是,基于scipy
的实施并不是最快的。我分析并发现scipy中的余弦需要花费大量时间将一个向量从python列表转换为numpy数组。
答案 5 :(得分:10)
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)))
答案 6 :(得分:4)
不使用任何导入
math.sqrt(x)的
可以替换为
x ** .5
不使用numpy.dot(),你必须使用列表理解创建自己的点函数:
def cosine_similarity(a,b):
return dot(a,b) / ( (dot(a,a) **.5) * (dot(b,b) ** .5) )
然后只是应用余弦相似公式的简单问题:
pip install tensorflow
答案 7 :(得分:3)
要计算的 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
答案 8 :(得分:2)
您可以使用简单的函数在Python中执行此操作:
def get_cosine(text1, text2):
vec1 = text1
vec2 = text2
intersection = set(vec1.keys()) & set(vec2.keys())
numerator = sum([vec1[x] * vec2[x] for x in intersection])
sum1 = sum([vec1[x]**2 for x in vec1.keys()])
sum2 = sum([vec2[x]**2 for x in vec2.keys()])
denominator = math.sqrt(sum1) * math.sqrt(sum2)
if not denominator:
return 0.0
else:
return round(float(numerator) / denominator, 3)
dataSet1 = [3, 45, 7, 2]
dataSet2 = [2, 54, 13, 15]
get_cosine(dataSet1, dataSet2)
答案 9 :(得分:2)
使用numpy将一个数字列表与多个列表(矩阵)进行比较:
def cosine_similarity(vector,matrix):
return ( np.sum(vector*matrix,axis=1) / ( np.sqrt(np.sum(matrix**2,axis=1)) * np.sqrt(np.sum(vector**2)) ) )[::-1]
答案 10 :(得分:1)
您可以使用此简单函数计算余弦相似度:
def cosine_similarity(a, b):
return sum([i*j for i,j in zip(a, b)])/(math.sqrt(sum([i*i for i in a]))* math.sqrt(sum([i*i for i in b])))
答案 11 :(得分:0)
如果您碰巧已经在使用PyTorch,则应该使用他们的CosineSimilarity implementation。
假设您有两个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
答案 12 :(得分:0)
另一种版本,如果您有一个向量列表和一个查询向量的场景,并且想要计算列表中所有向量的查询向量的余弦相似度,则可以在下面一次性完成时尚:
>>> import numpy as np
>>> A # list of vectors, shape -> m x n
array([[ 3, 45, 7, 2],
[ 1, 23, 3, 4]])
>>> B # query vector, shape -> 1 x n
array([ 2, 54, 13, 15])
>>> similarity_scores = A.dot(B)/ (np.linalg.norm(A, axis=1) * np.linalg.norm(B))
>>> similarity_scores
array([0.97228425, 0.99026919])
答案 13 :(得分: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)))
答案 14 :(得分:-3)
对于不能使用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
来确保分裂。