python - Python:两个大型numpy数组之间的余弦相似度

标签 python numpy scikit-learn cosine-similarity

我有两个numpy数组:

阵列1:500,000行x 100列

阵列2:160,000行x 100列

我想在数组1和数组2的每一行之间找到最大的余弦相似度。换句话说,我计算数组1的第一行与数组2的所有行之间的余弦相似度,并找到最大的余弦相似度,然后,我计算数组1中第二行与数组2中所有行之间的余弦相似度,并找到最大余弦相似度;并针对阵列1的其余部分执行此操作。

我目前使用sklearncosine_similarity()函数并执行以下操作,但是它非常慢。我想知道是否有一种更快的方式不涉及多处理/多线程来完成我想做的事情。另外,我拥有的数组也不稀疏。

from sklearn.metrics.pairwise import cosine_similarity as cosine

results = []
for i in range(Array1.shape[0]):
     results.append(numpy.max(cosine(Array1[None,i,:], Array2)))

最佳答案

在Python中进行迭代可能会很慢。最好总是“向量化”并尽可能多地对数组使用numpy操作,这会将工作传递给numpy的低级实现,这是快速的。

cosine_similarity已被矢量化。因此,理想的解决方案将只涉及cosine_similarity(A, B),其中A和B是您的第一个和第二个数组。不幸的是,这个矩阵是500,000 x 160,000,太大了,无法在内存中处理(它会引发错误)。

然后,下一个最佳解决方案是将A(按行)拆分为大块(而不是单个行),以便结果仍适合内存并对其进行迭代。我发现,在您的数据中,每个块中使用100行适合内存。还有很多,这是行不通的。然后,我们只需使用.max并为每次迭代获取100个最大值,最后我们可以将其收集在一起。

但是,这种方式强烈建议我们节省更多时间。两个向量的余弦相似度的公式为u.v / | u || v |,它是两者之间夹角的余弦。因为我们正在迭代,所以每次都会重新计算B行的长度并将结果扔掉。解决此问题的一种好方法是使用这样的事实:如果缩放矢量(角度相同),则余弦相似度不会改变。因此,我们只能计算一次所有的行长,然后将它们除以使行成为单位矢量。然后我们简单地以u.v计算余弦相似度,这可以通过矩阵乘法对数组进行。我对此进行了快速测试,速度大约快了3倍。

放在一起:

import numpy as np

# Example data
A = np.random.random([500000, 100])
B = np.random.random([160000, 100])

# There may be a proper numpy method for this function, but it won't be much faster.
def normalise(A):
    lengths = (A**2).sum(axis=1, keepdims=True)**.5
    return A/lengths

A = normalise(A)
B = normalise(B)

results = []

rows_in_slice = 100

slice_start = 0
slice_end = slice_start + rows_in_slice

while slice_end <= A.shape[0]:

    results.append(A[slice_start:slice_end].dot(B.T).max(axis=1))

    slice_start += rows_in_slice
    slice_end = slice_start + rows_in_slice

result = np.concatenate(results)


这需要大约每1000行A运行2秒。因此,您的数据大约需要1,000秒。

关于python - Python:两个大型numpy数组之间的余弦相似度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52030945/

相关文章:

python - 正则表达式匹配所有带有引号的句子

python - 使用 django 无限滚动

python - 你如何在 Python 中使用 numpy 处理自然日志(例如 "ln()")?

scikit-learn - CountVectorizer 的 sklearn 部分拟合

python - 无法使用 sklearn 加载 'mnist-original' 数据集

python - 'super' 对象没有属性 '__eq__'

python - NumPy:一次对许多小矩阵进行点积

python - 如何使用字典的值创建 numpy 数组?

python - FFT 未返回正确的幅度

python - 比较两个 Pandas Dataframe 中的数据的 bool 逻辑