2

我在 MongoDB 中有 n 个文档,其中包含一个 scipy 稀疏向量,存储为一个 pickle 对象,最初是用 scipy.sparse.lil 创建的。这些向量的大小都相同,比如 px 1。

我需要做的是将所有这些向量放入 python 中的稀疏 nxp 矩阵中。我正在使用 mongoengine 并因此定义了一个属性来加载每个泡菜向量:

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.3s。堆叠部分约2.7s。由于在未来 n 将严重增加(可能超过几十万),我觉得这不是最佳的 :) 有什么想法可以加快整个过程吗?如果您只知道如何固定“装载”或“堆叠”,我很高兴听到。例如,也许解决方案是将整个矩阵存储在 mongoDB 中?谢谢 !

4

2 回答 2

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,则更少。

于 2013-10-11T16:26:55.243 回答
1

我认为,您应该尝试使用ListField,它本质上是 BSON数组的 python 列表表示,来存储您的向量。在这种情况下,您不需要每次都解开它们。

    class MyClass(Document):

        vector = ListField()



    items = MyClass.objects()
    M = items[0].vector

我在该解决方案中看到的唯一问题是您必须将 python 列表转换为 scipy 稀疏向量类型,但我相信这应该更快。

于 2013-10-11T09:31:41.470 回答