mongodb到python稀疏矩阵,如何让它更快?

时间:2013-10-11 08:47:37

标签: python performance mongodb scipy sparse-matrix

我在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中?谢谢!

2 个答案:

答案 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稀疏矢量类型,但我相信,这应该更快。