Scipy 从索引列表和列表数据列表创建稀疏行矩阵

Scipy create sparse row matrix from a list of indices and a list of list data

假设我有一个列表数据列表,以及一个包含每个数据行号的列表,如何转换为稀疏矩阵?

示例:

import numpy as np
data = np.array([[1,2,3],[4,5,6],[7,8,9]])
indices = np.array([0,0,4]) # row number, sum when duplicated

预期输出为:

[[5, 7, 9], # row 0: [5,7,9]=[1,2,3]+[4,5,6]
 [0, 0, 0],
 [0, 0, 0],
 [7, 8, 9]] # row 4

我知道我可以使用 scipy.sparse.csr_matrix 和数据、row、col 或 indptr 来构造它,但是我现在已经计算了 dataindices,有没有使用这两个简单构造稀疏矩阵的方法?谢谢!

根据documentation,有一个直接利用CSR信息的构造函数:

csr_matrix((data, indices, indptr), [shape=(M, N)])

所以在你的具体情况下,你可以这样写:

data = np.array([1,2,3,4,5,6,7,8,9])
indices = np.array([0,1,2,0,1,2,0,1,2]) # col numbers
indptr = np.array([0,6,6,6,9]) # row pointers

mat = csr_matrix((data, indices, indptr), shape=(4, 3))

要获取有关 CSR 格式如何工作的示例,您可以查看 sparse matrices。尽管如此,我还是会解释代码:

首先,data 需要展平为一个列表。 CSR格式的indices索引相关,而indptr用于指向.

所以在列表的 位置 0 有一个 indptr0 告诉我们第一行 (position + 1) 的矩阵在 0 data 个条目之后开始。类似地,列表中 位置 1 处的值 6 告诉我们矩阵的第 2 行 (position + 1) 在 [=21= 之后开始] data 个条目。

column-indices 列表与您期望的一样:data[i] 位于 indices[i] 列。

In [131]: data = np.array([[1,2,3],[4,5,6],[7,8,9]])
     ...: indices = np.array([0,0,3]) # row number, sum when duplicated

我更正了基于 0 的索引的索引。

我们不需要 sparse 对重复项求和。有一个 np.add.at 可以很好地做到这一点:

In [135]: res = np.zeros((4,3),int)
In [136]: np.add.at(res, indices, data)
In [137]: res
Out[137]: 
array([[5, 7, 9],
       [0, 0, 0],
       [0, 0, 0],
       [7, 8, 9]])

如果我们从中得到 csr

In [141]: M = sparse.csr_matrix(res)
In [142]: M
Out[142]: 
<4x3 sparse matrix of type '<class 'numpy.int64'>'
    with 6 stored elements in Compressed Sparse Row format>
In [143]: M.data
Out[143]: array([5, 7, 9, 7, 8, 9])
In [144]: M.indices
Out[144]: array([0, 1, 2, 0, 1, 2], dtype=int32)
In [145]: M.indptr
Out[145]: array([0, 3, 3, 3, 6], dtype=int32)

要直接制作 csr,使用 coo 样式的输入通常更容易。它们更容易理解。

这些输入是 3 个相同大小的一维数组:

In [160]: data.ravel()
Out[160]: array([1, 2, 3, 4, 5, 6, 7, 8, 9])
In [161]: row = np.repeat(indices,3)
In [162]: row
Out[162]: array([0, 0, 0, 0, 0, 0, 3, 3, 3])
In [163]: col = np.tile(np.arange(3),3)
In [164]: col
Out[164]: array([0, 1, 2, 0, 1, 2, 0, 1, 2])
In [165]: M1 = sparse.coo_matrix((data.ravel(),(rows, cols)))
In [166]: M1.data
Out[166]: array([1, 2, 3, 4, 5, 6, 7, 8, 9])

coo 格式保留给定的输入;但在转换为 csr 时,重复项被求和。

In [168]: M2 = M1.tocsr()
In [169]: M2
Out[169]: 
<4x3 sparse matrix of type '<class 'numpy.int64'>'
    with 6 stored elements in Compressed Sparse Row format>
In [170]: M2.data
Out[170]: array([5, 7, 9, 7, 8, 9])
In [171]: M2.indices
Out[171]: array([0, 1, 2, 0, 1, 2], dtype=int32)
In [172]: M2.indptr
Out[172]: array([0, 3, 3, 3, 6], dtype=int32)

In [173]: M2.A
Out[173]: 
array([[5, 7, 9],
       [0, 0, 0],
       [0, 0, 0],
       [7, 8, 9]])

@Erik 展示了如何直接使用 csr 格式:

In [174]: M3 =sparse.csr_matrix((data.ravel(), col, [0,6,6,6,9]))
In [175]: M3
Out[175]: 
<4x3 sparse matrix of type '<class 'numpy.int64'>'
    with 9 stored elements in Compressed Sparse Row format>
In [176]: M3.A
Out[176]: 
array([[5, 7, 9],
       [0, 0, 0],
       [0, 0, 0],
       [7, 8, 9]])
In [177]: M3.indices
Out[177]: array([0, 1, 2, 0, 1, 2, 0, 1, 2], dtype=int32)

注意这有 9 个非零元素;它没有对存储的重复项求和(尽管 .A 显示显示它们已求和)。总而言之,我们需要一个额外的步骤:

In [179]: M3.sum_duplicates()
In [180]: M3.data
Out[180]: array([5, 7, 9, 7, 8, 9])