我深入研究了这两个版本的代码,并认为我了解两者都在做什么。
从一个小的简单X
(密集)开始:
X = np.arange(9.).reshape(3,3)
pdist
余弦会:
norms = _row_norms(X)
_distance_wrap.pdist_cosine_wrap(_convert_to_double(X), dm, norms)
行点在哪里_row_norms
- 使用einsum
:
norms = np.sqrt(np.einsum('ij,ij->i', X,X)
所以这是第一个X
必须是数组的地方。
我还没有深入研究 cosine_wrap,但它似乎可以(可能在 cython 中)
xy = np.dot(X, X.T)
# or xy = np.einsum('ij,kj',X,X)
d = np.zeros((3,3),float) # square receiver
d2 = [] # condensed receiver
for i in range(3):
for j in range(i+1,3):
val=1-xy[i,j]/(norms[i]*norms[j])
d2.append(val)
d[j,i]=d[i,j]=val
print('array')
print(d)
print('condensed',np.array(d2))
from scipy.spatial import distance
d1=distance.pdist(X,'cosine')
print(' pdist',d1)
生产:
array
[[ 0. 0.11456226 0.1573452 ]
[ 0.11456226 0. 0.00363075]
[ 0.1573452 0.00363075 0. ]]
condensed [ 0.11456226 0.1573452 0.00363075]
pdist [ 0.11456226 0.1573452 0.00363075]
distance.squareform(d1)
d
产生与我的数组相同的东西。
xy
我可以通过将点积与适当的norm
外积相除来生成相同的方阵:
dd=1-xy/(norms[:,None]*norms)
dd[range(dd.shape[0]),range(dd.shape[1])]=0 # clean up 0s
X
或者在采用点积之前进行标准化。这似乎是scikit
版本所做的。
Xnorm = X/norms[:,None]
1-np.einsum('ij,kj',Xnorm,Xnorm)
scikit
添加了一些 cython 代码来进行更快的稀疏计算(超出 提供的那些sparse.sparse
,但使用相同的csr
格式):
from scipy import sparse
Xc=sparse.csr_matrix(X)
# csr_row_norm - pyx of following
cnorm = Xc.multiply(Xc).sum(axis=1)
cnorm = np.sqrt(cnorm)
X1 = Xc.multiply(1/cnorm) # dense matrix
dd = 1-X1*X1.T
要获得具有稀疏矩阵的快速压缩形式,我认为您需要实现X1*X1.T
. 这意味着您需要了解如何在c
代码中实现稀疏矩阵乘法。cython scikit
'fast sparse' 代码也可能提供一些想法。
numpy
有一些tri...
函数是直接的 Python 代码。它不会试图通过直接实施三计算来节省时间或空间。迭代 nd 数组的矩形布局(具有形状和步幅)比执行更复杂的三角形数组的可变长度步骤更容易。精简的形式只是将空间和计算步骤减少了一半。
=============
c
这是函数 的主要部分pdist_cosine
,它迭代i
和上层j
,计算dot(x[i],y[j])/(norm[i]*norm[j])
。
for (i = 0; i < m; i++) {
for (j = i + 1; j < m; j++, dm++) {
u = X + (n * i);
v = X + (n * j);
cosine = dot_product(u, v, n) / (norms[i] * norms[j]);
if (fabs(cosine) > 1.) {
/* Clip to correct rounding error. */
cosine = npy_copysign(1, cosine);
}
*dm = 1. - cosine;
}
}
https://github.com/scipy/scipy/blob/master/scipy/spatial/src/distance_impl.h