mongodb到python稀疏矩阵,如何让它更快?
我在MongoDB中有n个文档,其中包含一个scipy稀疏向量,存储为pickle对象,最初使用scipy.sparse.lil创建。向量都是相同大小的,比如px1 我需要做的是将所有这些向量放到python中的稀疏Nxp矩阵中。我正在使用mongoengine,因此定义了一个属性来加载每个pickle向量:mongodb到python稀疏矩阵,如何让它更快?,python,performance,mongodb,scipy,sparse-matrix,Python,Performance,Mongodb,Scipy,Sparse Matrix,我在MongoDB中有n个文档,其中包含一个scipy稀疏向量,存储为pickle对象,最初使用scipy.sparse.lil创建。向量都是相同大小的,比如px1 我需要做的是将所有这些向量放到python中的稀疏Nxp矩阵中。我正在使用mongoengine,因此定义了一个属性来加载每个pickle向量: class MyClass(Document): vector_text = StringField() @property def vector(self):
class MyClass(Document):
vector_text = StringField()
@property
def vector(self):
return cPickle.loads(self.vector_text)
这是我现在做的,n=4700,p=67:
items = MyClass.objects()
M = items[0].vector
for item in items[1:]:
to_add = item.vector
M = scipy.sparse.hstack((M, to_add))
加载部分(即调用n次属性)大约需要1.3秒。堆叠部分约为2.7s。因为在未来n将严重增加(可能超过几十万),我感觉这不是最优的:)
有没有加快整个过程的想法?如果你只知道如何固定“装载”或“堆叠”,我很高兴听到。例如,也许解决方案是将整个矩阵存储在mongoDB中?谢谢 我认为,您应该尝试使用,它本质上是BSON数组的python列表表示形式来存储向量。在这种情况下,您不必每次都解开它们
class MyClass(Document):
vector = ListField()
items = MyClass.objects()
M = items[0].vector
我在该解决方案中看到的唯一问题是,您必须将python列表转换为scipy稀疏向量类型,但我认为,这应该更快。首先,您所描述的您想要做的是使用
vstack
,而不是hstack
。在任何情况下,稀疏格式的选择都是性能问题的一部分。请尝试以下操作:
n, p = 4700, 67
csr_vecs = [sps.rand(1, p, density=0.5, format='csr') for j in xrange(n)]
lil_vecs = [vec.tolil() for vec in csr_vecs]
%timeit sps.vstack(csr_vecs, format='csr')
1 loops, best of 3: 722 ms per loop
%timeit sps.vstack(lil_vecs, format='lil')
1 loops, best of 3: 1.34 s per loop
因此,从swithcing到CSR已经有了2倍的改进。此外,scipy.sparse
的叠加函数似乎没有得到很好的优化,对于稀疏向量肯定没有。以下两个函数堆叠CSR或LIL向量列表,返回CSR稀疏矩阵:
def csr_stack(vectors):
data = np.concatenate([vec.data for vec in vectors])
indices = np.concatenate([vec.indices for vec in vectors])
indptr = np.cumsum([0] + [vec.nnz for vec in vectors])
return sps.csr_matrix((data, indices, indptr), shape=(len(vectors),
vectors[0].shape[1]))
import itertools as it
def lil_stack(vectors):
indptr = np.cumsum([0] + [vec.nnz for vec in vectors])
data = np.fromiter(it.chain(*(vec.data[0] for vec in vectors)),
dtype=vectors[0].dtype, count=indptr[-1])
indices = np.fromiter(it.chain(*(vec.rows[0] for vec in vectors)),
dtype=np.intp, count=indptr[-1])
return sps.csr_matrix((data, indices, indptr), shape=(len(vectors),
vectors[0].shape[1]))
它的工作原理是:
>>> np.allclose(sps.vstack(csr_vecs).A, csr_stack(csr_vecs).A)
True
>>> np.allclose(csr_stack(csr_vecs).A, lil_stack(lil_vecs).A)
True
而且速度大大加快:
%timeit csr_stack(csr_vecs)
100 loops, best of 3: 11.7 ms per loop
%timeit lil_stack(lil_vecs)
10 loops, best of 3: 37.6 ms per loop
%timeit lil_stack(lil_vecs).tolil()
10 loops, best of 3: 53.6 ms per loop
因此,通过切换到CSR,您可以将性能提高100倍以上。如果你坚持LIL,你的绩效提升将只有30倍左右,如果你能在组合矩阵中接受CSR,提升幅度会更大,如果你坚持LIL,提升幅度会更小。有趣。如果vector是一个numpy数组或一个列表,它就像一个符咒。似乎存储稀疏向量比较困难。但就像你说的,我可以在事后再转换。这是第一步,它会加快速度,谢谢!真是令人印象深刻,我肯定要换了!使用Jaime和Alexander的答案,我的程序现在真的非常快(事实证明,当你的程序基于运行数千次相同的方法,并且你使所述方法快100倍时,我可能不需要说:))。太棒了,谢谢。