私は大きなスパースバイナリ行列を扱っています。私はScipy
スパース行列の実装を使用してそれらを凝縮しました。 scipy.spatial.distance
からJaccard distance
の計算は、スパース行列に直接操作をサポートしていないので、次のいずれかgetrow()に対するScipyスパース行列の代替方法
緻密に全体疎行列を変換した後、空腹メモリ
あるベクターとして、各行で動作しますまたは
ループを散りばめ、各行をつかみ、
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()
は実装が遅くなっているようです。 scipy.spatial.distance.jaccard
に対するIベンチマークjaccard_fast
ように、結果は以下のとおりです。
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)なので、その上でzipし、 'mat'は最小の行数で繰り返します。 1. – hpaulj
'benchmark_jaccard_internal_getrow'は有効なテストではありません。あなた自身の承認で' d.jaccard'がスパースで動作しないからです。 – hpaulj