2个数字列表之间的余弦相似度

Rob*_*sod 101 python python-3.x cosine-similarity

我需要计算两个列表之间的余弦相似度,比如列表1,列表2是.我不能使用numpy或统计模块等任何东西.我必须使用通用模块(数学等)(尽可能使用最少的模块,以减少花费的时间).dataSetIdataSetII

比方说,dataSetI[3, 45, 7, 2]dataSetII[2, 54, 13, 15].列表的长度始终相等.

当然,余弦相似度在0和1之间,并且为了它,它将四舍五入到第三或第四个十进制数format(round(cosine, 3)).

非常感谢您提前帮助.

cha*_*umQ 145

你应该尝试SciPy.它有一堆有用的科学例程,例如"用数字计算积分,求解微分方程,优化和稀疏矩阵的例程".它使用超高速优化的NumPy进行数字运算.请看这里安装.

请注意,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)
Run Code Online (Sandbox Code Playgroud)


don*_*loo 71

另一个版本numpy仅基于

from numpy import dot
from numpy.linalg import norm

cos_sim = dot(a, b)/(norm(a)*norm(b))
Run Code Online (Sandbox Code Playgroud)

  • 定义非常清楚,但也许`np.inner(a, b) / (norm(a) * norm(b))`更好理解。`dot` 可以获得与向量的 `inner` 相同的结果。 (5认同)
  • 仅供参考,该解决方案在我的系统上比使用`scipy.spatial.distance.cosine`要快得多。 (5认同)
  • 更短:`cos_sim = (a @ bT) / (norm(a)*norm(b))` (4认同)

Aka*_*all 60

您可以使用cosine_similarity函数表单sklearn.metrics.pairwise 文档

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

In [24]: cosine_similarity([[1, 0, -1]], [[-1,-1, 0]])
Out[24]: array([[-0.5]])
Run Code Online (Sandbox Code Playgroud)

  • 只是提醒一下,在sklearn版本0.17中不推荐将一维数组作为输入数据传递,并且会在0.19中引发ValueError. (18认同)
  • 用一个括号`cosine_similarity([[1,0,-1]],[[ - -1,-1,0]])括起来. (9认同)
  • 在给出此弃用警告的情况下,使用sklearn执行此操作的正确方法是什么? (4认同)
  • @Elliott one_dimension_array.reshape(-1,1) (2认同)
  • @ bobo32余弦相似度(np.array([1,0,-1])。reshape(-1,0),np.array([-1,-1,0])。reshape(-1,0))我你猜是什么意思?但是,该结果意味着它返回了什么?它是一个新的2d数组,而不是余弦相似度。 (2认同)

Mik*_*sky 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
Run Code Online (Sandbox Code Playgroud)

这就是一次一个地提取元素的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
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,unpythonic方式快约3.6倍.

  • 我猜对了.但它没有用.您提供两种算法的时间比较,但只显示其中一种算法. (3认同)
  • 在这种情况下,什么是`cosine_measure`? (2认同)

McK*_*vin 13

我根据问题中的几个答案做了基准测试,以下片段被认为是最佳选择:

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)
Run Code Online (Sandbox Code Playgroud)

结果让我感到惊讶的是,基于的实现scipy不是最快的.我分析并发现scipy中的余弦需要花费大量时间将一个向量从python列表转换为numpy数组.

在此输入图像描述


pka*_*zak 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)
Run Code Online (Sandbox Code Playgroud)

您可以在计算后将其舍入:

cosine = format(round(cosine_measure(v1, v2), 3))
Run Code Online (Sandbox Code Playgroud)

如果你想要它真的很短,你可以使用这个单线:

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)))
Run Code Online (Sandbox Code Playgroud)


Isi*_*ira 8

您可以使用这个简单的函数来计算余弦相似度:

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])))
Run Code Online (Sandbox Code Playgroud)


Moh*_*med 8

不使用任何进口

math.sqrt(x)

可以替换为

x ** .5

在不使用numpy.dot()的情况下,您必须使用列表理解来创建自己的点函数:

def dot(A,B): 
    return (sum(a*b for a,b in zip(A,B)))
Run Code Online (Sandbox Code Playgroud)

然后只需应用余弦相似度公式即可:

def cosine_similarity(a,b):
    return dot(a,b) / ( (dot(a,a) **.5) * (dot(b,b) ** .5) )
Run Code Online (Sandbox Code Playgroud)


Ami*_*yan 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
Run Code Online (Sandbox Code Playgroud)