【发布时间】:2016-09-01 10:43:04
【问题描述】:
我正在处理大型稀疏二进制矩阵。我使用Scipy 稀疏矩阵实现对它们进行了压缩。从scipy.spatial.distance计算Jaccard distance不支持对稀疏矩阵的直接运算,所以要么:
-
将整个稀疏矩阵转换为密集矩阵,然后将每一行作为向量进行操作,这需要大量内存
或
-
遍历稀疏,使用
getrow()抓取每一行并进行操作。或
-
编写我们自己的实现来处理稀疏矩阵。
为了让事情更清楚,这里是示例代码:
import scipy.spatial.distance as d
import numpy as np
from scipy.sparse import csr_matrix
# benchmark performance
X = np.random.random((3000, 3000))
# binarize
X[X > 0.3] = 0
X[X>0] = 1
mat = csr_matrix(X)
a = np.zeros(3000)
a[4] = a[100] = a[22] =1
a = csr_matrix(a)
def jaccard_fast(v1,v2):
common = v1.dot(v2.T)
dis = (v1 != v2).getnnz()
if common[0,0]:
return 1.0-float(common[0,0])/float(common[0,0]+dis)
else:
return 0.0
def benchmark_jaccard_fast():
for i in range(mat.shape[0]):
jaccard_fast(mat.getrow(i),a)
def benchmark_jaccard_internal_todense():
for v1,v2 in zip(mat.todense(),a.todense()):
d.jaccard(v1,v2)
def benchmark_jaccard_internal_getrow():
for i in range(mat.shape[0]):
d.jaccard(mat.getrow(i),a)
print "Jaccard Fast:"
%time benchmark_jaccard_fast()
print "Jaccard Scipy (expanding to dense):"
%time benchmark_jaccard_internal_todense()
print "Jaccard Scipy (using getrow):"
%time benchmark_jaccard_internal_getrow()
jaccard_fast 是我自己的实现。在 scipy 稀疏矩阵上,我的实现似乎比内部实现要快,但是 getrow() 似乎减慢了我的实现速度。当我将 jaccard_fast 与 scipy.spatial.distance.jaccard 进行基准测试时,结果是:
Jaccard Fast:
CPU times: user 1.28 s, sys: 0 ns, total: 1.28 s
Wall time: 1.28 s
Jaccard Scipy (expanding to dense):
CPU times: user 28 ms, sys: 8 ms, total: 36 ms
Wall time: 37.2 ms
Jaccard Scipy (using getrow):
CPU times: user 1.82 s, sys: 0 ns, total: 1.82 s
Wall time: 1.81 s
任何有关如何避免getrow 瓶颈的帮助将不胜感激。由于内存限制,我无法使用todense() 扩展我的稀疏矩阵。
【问题讨论】:
-
我认为你的
benchmark_jaccard_internal_todense是在作弊。它没有进行完整的 3000 次迭代。a.todense()是 (1,3000),所以压缩它,mat迭代最少的行数 - 即。 1. -
benchmark_jaccard_internal_getrow不是一个有效的测试,因为您自己承认d.jaccard不适用于稀疏。
标签: python scipy sparse-matrix