矢量化是比较容易,如果你使用的矩阵乘法计算交点集内,然后将规则|union(a, b)| == |a| + |b| - |intersection(a, b)|
确定工会:
# Not actually necessary for sparse matrices, but it is for
# dense matrices and ndarrays, if X.dtype is integer.
from __future__ import division
def pairwise_jaccard(X):
"""Computes the Jaccard distance between the rows of `X`.
"""
X = X.astype(bool).astype(int)
intrsct = X.dot(X.T)
row_sums = intrsct.diagonal()
unions = row_sums[:,None] + row_sums - intrsct
dist = 1.0 - intrsct/unions
return dist
注投为bool然后int,因为X
的dtype必须足够大以累积最大行总和的两倍,并且X
的条目必须为零或一。这个代码的缺点是RAM很重,因为unions
和dists
是密集矩阵。
如果你只关心的距离小于一些截止epsilon
,可以将代码调整为稀疏矩阵:
from scipy.sparse import csr_matrix
def pairwise_jaccard_sparse(csr, epsilon):
"""Computes the Jaccard distance between the rows of `csr`,
smaller than the cut-off distance `epsilon`.
"""
assert(0 < epsilon < 1)
csr = csr_matrix(csr).astype(bool).astype(int)
csr_rownnz = csr.getnnz(axis=1)
intrsct = csr.dot(csr.T)
nnz_i = np.repeat(csr_rownnz, intrsct.getnnz(axis=1))
unions = nnz_i + csr_rownnz[intrsct.indices] - intrsct.data
dists = 1.0 - intrsct.data/unions
mask = (dists > 0) & (dists <= epsilon)
data = dists[mask]
indices = intrsct.indices[mask]
rownnz = np.add.reduceat(mask, intrsct.indptr[:-1])
indptr = np.r_[0, np.cumsum(rownnz)]
out = csr_matrix((data, indices, indptr), intrsct.shape)
return out
如果这仍然需要以多少RAM你可以尝试向量化了一个维和Python循环。
您能详细说明导致运行时的实现细节吗? – Ryan
啊,对不起。已添加代码。 –
我会首先使用(推测)优化的jaccard函数,例如http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.jaccard.html – Ryan