【问题标题】:What is the fastest way to slice a scipy.sparse matrix?切片 scipy.sparse 矩阵的最快方法是什么?
【发布时间】:2012-11-30 08:51:43
【问题描述】:

我一般用

matrix[:, i:]

它似乎没有我预期的那么快。

【问题讨论】:

  • 介意为我们进行基准测试吗?甚至可以使用timeit

标签: python numpy scipy sparse-matrix


【解决方案1】:

如果您想获得一个稀疏矩阵作为输出,进行行切片的最快方法是使用csr 类型,对于列切片cscas detailed here。在这两种情况下,你只需要做你目前正在做的事情:

matrix[l1:l2,c1:c2]

如果您想要另一种类型作为输出,可能会有更快的方法。 In this other answer 解释了许多对矩阵进行切片的方法,并比较了它们的不同时间。例如,如果你想要一个ndarray 作为输出,最快的切片是:

matrix.A[l1:l2,c1:c2] 

或:

matrix.toarray()[l1:l2,c1:c2]

比:快得多:

matrix[l1:l2,c1:c2].A #or .toarray()

【讨论】:

  • 但是如果矩阵很大,matrix.A会导致memoryError。
【解决方案2】:

我发现scipy.sparse.csr_matrix 所宣传的快速行索引可以通过滚动您自己的行索引器来加快速度。思路是这样的:

class SparseRowIndexer:
    def __init__(self, csr_matrix):
        data = []
        indices = []
        indptr = []

        # Iterating over the rows this way is significantly more efficient
        # than csr_matrix[row_index,:] and csr_matrix.getrow(row_index)
        for row_start, row_end in zip(csr_matrix.indptr[:-1], csr_matrix.indptr[1:]):
             data.append(csr_matrix.data[row_start:row_end])
             indices.append(csr_matrix.indices[row_start:row_end])
             indptr.append(row_end-row_start) # nnz of the row

        self.data = np.array(data)
        self.indices = np.array(indices)
        self.indptr = np.array(indptr)
        self.n_columns = csr_matrix.shape[1]

    def __getitem__(self, row_selector):
        data = np.concatenate(self.data[row_selector])
        indices = np.concatenate(self.indices[row_selector])
        indptr = np.append(0, np.cumsum(self.indptr[row_selector]))

        shape = [indptr.shape[0]-1, self.n_columns]

        return sparse.csr_matrix((data, indices, indptr), shape=shape)

也就是说,可以通过将每行的非零值存储在单独的数组中(每行的长度不同)并将所有这些行数组放在一个对象中来利用 numpy 数组的快速索引 -可以有效索引的类型化数组(允许每一行具有不同的大小)。列索引的存储方式相同。该方法与将所有非零值存储在单个数组中的标准 CSR 数据结构略有不同,需要查找以查看每一行的开始和结束位置。这些查找可能会减慢随机访问速度,但对于检索连续行应该是有效的。

分析结果

我的矩阵 mat 是一个 1,900,000x1,250,000 csr_matrix 有 400,000,000 个非零元素。 ilocs 是一个包含 200,000 个随机行索引的数组。

>>> %timeit mat[ilocs]
2.66 s ± 233 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

相比:

>>> row_indexer = SparseRowIndexer(mat)
>>> %timeit row_indexer[ilocs]
59.9 ms ± 4.51 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

与布尔掩码相比,使用精美索引时,SparseRowIndexer 似乎更快。

【讨论】:

    猜你喜欢
    • 2012-12-31
    • 2016-02-06
    • 1970-01-01
    • 2016-09-26
    • 1970-01-01
    • 2013-05-20
    • 1970-01-01
    相关资源
    最近更新 更多