【问题标题】:What is the best way to implement an element-wise cosine similarity in Python?在 Python 中实现元素余弦相似度的最佳方法是什么?
【发布时间】:2019-07-09 06:11:14
【问题描述】:

对于大型矩阵,下面的代码效率非常低。有没有更好的方法来实现这个?

我已经在网上搜索过这个here

import numpy as np

def cosine_similarity(x, y):
    return np.dot(x, y) / (np.sqrt(np.dot(x, x)) * np.sqrt(np.dot(y, y)))

def compare(a, b):

    c = np.zeros((a.shape[0], b.shape[0]))

    for i, ai in enumerate(a):
        for j, bj in enumerate(b):
            c[i, j] = cosine_similarity(ai, bj)

    return c

a = np.random.rand(100,2000)
b = np.random.rand(800,2000)

compare(a,b) # shape -> (100, 800)

【问题讨论】:

  • a.dot(b.T) 怎么样?
  • @Divakar 不是 a@b.T?
  • @Dan 应该是一样的。 @ 特定于 Python3.x。
  • @Divakar 很有趣,我没想到 dot 会使用 len(a.shape) != 1 处理矩阵
  • 这个函数为什么叫compare()?这不就是矩阵乘法吗?

标签: python cosine-similarity


【解决方案1】:

就像在 cmets 中一样,如果你想取两个矩阵的乘积,那么 numpy 已经有一个有效的实现,但它对你来说可能太慢了 (O(n^3))。

import numpy as np

a=np.array([3,2,1])
b=np.array([1,2,3])
c=a.dot(b)
print(c) #output = 10

我在 cmets 中看到您对向量之间的余弦距离感兴趣。对于余弦相似度,请考虑使用 Scipy:

from scipy.spatial.distance import cosine

a=[1,0,1]
b=[0,1,0]
print(cosine(a,b)) #output = 1.0

根据您的需要,这可能会更快。这是documentation

【讨论】:

  • 谢谢,我尝试过使用 Scipy 但不幸的是它并没有提高效率。尽管如此,我已经编写了一个更快的实现,我将把它作为答案发布
【解决方案2】:

[个人编辑]

为了有效地计算余弦相似度,这是我写的一个解决方案:

def compare(a, b):
    x = np.atleast_2d(np.sqrt(np.sum(a*a, axis=1))).T
    y = np.atleast_2d(np.sqrt(np.sum(b*b, axis=1))).T
    return a.dot(b.T) / x.dot(y.T)

【讨论】:

  • 你试过cdist吗?
  • 感谢您介绍此解决方案,我已尝试使用以下代码cdist(a, b, cosine_similarity)。结果是一样的,但速度仍然较慢。
  • 按照文档尝试cdist(a, b, 'cosine')。这还具有已经经过彻底的单元和用户测试的优势。
  • 由于他们的定义有点不同,我必须做- (cdist(a, b, 'cosine') - 1)。如果输入分别是 a = np.random.rand(100,20000)b = np.random.rand(800,20000) 我得到 2.26sec (cdist) vs 0.14sec
猜你喜欢
  • 2021-09-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-15
  • 2020-08-12
  • 1970-01-01
  • 2012-11-19
  • 2011-01-01
相关资源
最近更新 更多