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

两个数组之间的余弦距离计算-Python,python,arrays,performance,numpy,vectorization,Python,Arrays,Performance,Numpy,Vectorization,我想应用一个函数fn,它本质上是余弦距离在两个大的numpy形状数组(10000,100)和(5000,100)行上进行计算,也就是说,我为这些数组中的每一行组合计算一个值 我的实施: 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 +=

我想应用一个函数
fn
,它本质上是
余弦距离
在两个大的numpy形状数组(10000,100)和(5000,100)行上进行计算,也就是说,我为这些数组中的每一行组合计算一个值

我的实施:

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:我们可以简单地使用它的
余弦
距离功能-

from scipy.spatial.distance import cdist

val_out = 1 - cdist(array1, array2, 'cosine')
方法#2:使用-

方法#3:用于计算另一个方法的自平方和-

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:
平方根的计算转移到另一种方法中-

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
方法#1:我们可以简单地使用它的
余弦
距离功能-

from scipy.spatial.distance import cdist

val_out = 1 - cdist(array1, array2, 'cosine')
方法#2:使用-

方法#3:用于计算另一个方法的自平方和-

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:
平方根的计算转移到另一种方法中-

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

fn
计算两个向量之间的余弦相似性。我更新了问题
fn
计算两个向量之间的余弦相似性。我更新了问题,
cdist
似乎已经做了1次减法。因此没有必要再做一次。看起来
cdist
已经做了1次减法。因此,没有必要再这样做。