python - 两个数组之间的余弦距离计算 - Python

标签 python arrays performance numpy vectorization

<分区>

我想应用一个函数 fn,它本质上是对两个形状为 (10000, 100) 和 (5000, 100) 行的大型 numpy 数组进行 余弦距离 计算-明智的,即我为这些数组中的每个行组合计算一个值。

我的实现:

import math
def fn(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)
val = []
for i in range(array1.shape[0]):
    for j in range(array2.shape[0]):
        val.append(fn(array1[i, :], array2[j, :]))

这个函数非常快,只需要几毫秒:

CPU times: user 4 ms, sys: 0 ns, total: 4 ms
Wall time: 1.24 ms

有什么有效的方法吗?

最佳答案

方法 #1: 我们可以简单地使用 Scipy's cdist及其 cosine 距离功能 -

from scipy.spatial.distance import cdist

val_out = 1 - cdist(array1, array2, 'cosine')

方法 #2: 另一种使用 matrix-multiplication 的方法-

def cosine_vectorized(array1, array2):
    sumyy = (array2**2).sum(1)
    sumxx = (array1**2).sum(1, keepdims=1)
    sumxy = array1.dot(array2.T)
    return (sumxy/np.sqrt(sumxx))/np.sqrt(sumyy)

方法#3:使用np.einsum计算另一个的自平方和 -

def cosine_vectorized_v2(array1, array2):
    sumyy = np.einsum('ij,ij->i',array2,array2)
    sumxx = np.einsum('ij,ij->i',array1,array1)[:,None]
    sumxy = array1.dot(array2.T)
    return (sumxy/np.sqrt(sumxx))/np.sqrt(sumyy)

方法#4:引入numexpr module为另一种方法卸载 square-root 计算 -

import numexpr as ne

def cosine_vectorized_v3(array1, array2):
    sumyy = np.einsum('ij,ij->i',array2,array2)
    sumxx = np.einsum('ij,ij->i',array1,array1)[:,None]
    sumxy = array1.dot(array2.T)
    sqrt_sumxx = ne.evaluate('sqrt(sumxx)')
    sqrt_sumyy = ne.evaluate('sqrt(sumyy)')
    return ne.evaluate('(sumxy/sqrt_sumxx)/sqrt_sumyy')

运行时测试

# Using same sizes as stated in the question
In [185]: array1 = np.random.rand(10000,100)
     ...: array2 = np.random.rand(5000,100)
     ...: 

In [194]: %timeit 1 - cdist(array1, array2, 'cosine')
1 loops, best of 3: 366 ms per loop

In [195]: %timeit cosine_vectorized(array1, array2)
1 loops, best of 3: 287 ms per loop

In [196]: %timeit cosine_vectorized_v2(array1, array2)
1 loops, best of 3: 283 ms per loop

In [197]: %timeit cosine_vectorized_v3(array1, array2)
1 loops, best of 3: 217 ms per loop

关于python - 两个数组之间的余弦距离计算 - Python,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43493235/

相关文章:

javascript - 按两个属性排序,其中一个属性优先但具有共同值?

Java,从数组中查找第 K 个最大值

python - 从磁盘读取列表会比加载字典更好吗?

javascript - 更改对 JSON 对象的调用以使程序更加抽象

python - 从 GoogleAppEngine 模型中删除重复项?

python - @classmethod 的使用如何导致输出差异?

c++ - 如何在不构建模块的情况下将 C++ 类公开给 Python

c - 具有未知项的多维数组

css - 在网络上加载高分辨率图像是否有良好的非阻塞模式?

python - 没有发送(或接收)队列的 Unix Socket