我在MongoDB中有n个文件,包含一个scipy稀疏向量,存储为pickle对象,最初用scipy.sparse.lil创建。矢量都是相同的大小,比如p x 1.
我需要做的是将所有这些向量放入python中的稀疏n x p矩阵中。我正在使用mongoengine,因此定义了一个属性来加载每个pickle矢量:
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中?谢谢!
答案 0 :(得分:4)
首先,您要描述的内容要求您使用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
因此,从转换到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,则会更少。
答案 1 :(得分:1)
我认为,您应该尝试使用ListField来存储您的向量,它基本上是BSON 数组的python列表表示。在那种情况下,你不需要每次都去除它们。
class MyClass(Document):
vector = ListField()
items = MyClass.objects()
M = items[0].vector
我在该解决方案中可以看到的唯一问题是,你必须将python列表转换为scipy稀疏矢量类型,但我相信,这应该更快。