Scipy CSR之间更快的Python余弦差异”;向量;
这是一个经典的问题,但我相信很多人仍在寻找答案。 这个问题不同于,因为我的问题是两个稀疏向量(不是矩阵)之间的运算 我写了一篇关于余弦Scipy空间距离(SSD)在数据维度越来越高时变得越来越慢的文章(因为它在密集向量上工作)。这篇文章是用印尼语写的,但是代码、我的实验设置和结果应该很容易理解,不管是哪种语言(在文章的底部) 目前,此解决方案用于高维数据(与SSD相比)的速度快70多倍,并且内存效率更高:Scipy CSR之间更快的Python余弦差异”;向量;,python,cython,sparse-matrix,jit,numba,Python,Cython,Sparse Matrix,Jit,Numba,这是一个经典的问题,但我相信很多人仍在寻找答案。 这个问题不同于,因为我的问题是两个稀疏向量(不是矩阵)之间的运算 我写了一篇关于余弦Scipy空间距离(SSD)在数据维度越来越高时变得越来越慢的文章(因为它在密集向量上工作)。这篇文章是用印尼语写的,但是代码、我的实验设置和结果应该很容易理解,不管是哪种语言(在文章的底部) 目前,此解决方案用于高维数据(与SSD相比)的速度快70多倍,并且内存效率更高: import numpy as np def fCosine(u,v):
import numpy as np
def fCosine(u,v): # u,v CSR vectors, Cosine Dissimilarity
uData = u.data; vData = v.data
denominator = np.sqrt(np.sum(uData**2)) * np.sqrt(np.sum(vData**2))
if denominator>0:
uCol = u.indices; vCol = v.indices # np array
intersection = set(np.intersect1d(uCol,vCol))
uI = np.array([u1 for i,u1 in enumerate(uData) if uCol[i] in intersection])
vI = np.array([v2 for j,v2 in enumerate(vData) if vCol[j] in intersection])
return 1-np.dot(uI,vI)/denominator
else:
return float("inf")
是否有可能进一步改进该功能(Pythonic或通过JIT/Cython???。这里有一个替代方案,
alt\u fCosine
,它(在我的机器上)对于大小为10**5
和10**4
非零元素的CSR向量,速度大约快3倍:
import scipy.sparse as sparse
import numpy as np
import math
def fCosine(u,v): # u,v CSR vectors, Cosine Dissimilarity
uData = u.data; vData = v.data
denominator = np.sqrt(np.sum(uData**2)) * np.sqrt(np.sum(vData**2))
if denominator>0:
uCol = u.indices; vCol = v.indices # np array
intersection = set(np.intersect1d(uCol,vCol))
uI = np.array([u1 for i,u1 in enumerate(uData) if uCol[i] in intersection])
vI = np.array([v2 for j,v2 in enumerate(vData) if vCol[j] in intersection])
return 1-np.dot(uI,vI)/denominator
else:
return float("inf")
def alt_fCosine(u,v):
uData, vData = u.data, v.data
denominator = math.sqrt(np.sum(uData**2) * np.sum(vData**2))
if denominator>0:
uCol, vCol = u.indices, v.indices
uI = uData[np.in1d(uCol, vCol)]
vI = vData[np.in1d(vCol, uCol)]
return 1-np.dot(uI,vI)/denominator
else:
return float("inf")
# Check that they return the same result
N = 10**5
u = np.round(10*sparse.random(1, N, density=0.1, format='csr'))
v = np.round(10*sparse.random(1, N, density=0.1, format='csr'))
assert np.allclose(fCosine(u, v), alt_fCosine(u, v))
alt\u fCosine
替换了两个列表理解,即调用np.intersection1d
以及通过对np.inad
和advanced的两次调用形成Python集
索引
对于
N=10**5
:
In [322]: %timeit fCosine(u, v)
100 loops, best of 3: 5.73 ms per loop
In [323]: %timeit alt_fCosine(u, v)
1000 loops, best of 3: 1.62 ms per loop
In [324]: 5.73/1.62
Out[324]: 3.537037037037037
太棒了,非常感谢。。。我想知道为什么math.sqrt比numpy.sqrt快?一般来说,数学对于简单域(标量/列表)更快吗?是的,
math.sqrt
对于标量更快。我怀疑math
模块中的所有函数也是如此,因为与相应的NumPy函数不同,它们不必测试备用代码路径(如果array这样做,如果iterable这样做,等等)。