我想计算两个列表之间的余弦相似度,比如说,列表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))
我根据问题中的几个答案做了一个基准测试,下面的代码片段被认为是最好的选择:
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数组。
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)))
这里有一个实现,也适用于矩阵。它的行为完全像sklearn余弦相似度:
def cosine_similarity(a, b):
return np.divide(
np.dot(a, b.T),
np.linalg.norm(
a,
axis=1,
keepdims=True
)
@ # matrix multiplication
np.linalg.norm(
b,
axis=1,
keepdims=True
).T
)
符号@代表矩阵乘法。看到
“at”(@)符号在Python中有什么作用?
你应该试试SciPy。它有一堆有用的科学例程,例如,“用于数值计算积分、求解微分方程、优化和稀疏矩阵的例程。”它使用超高速优化的NumPy进行数字处理。请参见此处安装。
注意,space .distance.cos计算距离,而不是相似度。所以,你必须用1减去这个值才能得到相似度。
from scipy import spatial
dataSetI = [3, 45, 7, 2]
dataSetII = [2, 54, 13, 15]
result = 1 - spatial.distance.cosine(dataSetI, dataSetII)