我正在学习稀疏矩阵运算的密码。但是,我对执行加法运算时如何计算csr_matrix索引感到困惑。我的代码很简单:
B = A + A.T
A.toarray()
array([[1., 1., 1., 1., 0., 1., 1., 0., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.]])
A.indices:
array([ 0, 2, 1, 5, 10, 3, 6, 11, 9, 8,
1, 2, 9, 10, 5, 8, 6, 11, 3, 7,
2, 10, 1, 5, 9, 6, 11, 7, 8, 3,
3, 8, 6, 7, 5, 11, 9, 10, 2, 1,
4, 9, 1, 7, 8, 11, 3, 6, 10, 5,
5, 6, 11, 10, 8, 9, 3, 2, 7, 1,
6, 5, 8, 11, 9, 10, 3, 7, 2, 1,
7, 9, 3, 6, 8, 5, 11, 10, 2, 1,
8, 6, 11, 9, 5, 3, 10, 7, 1, 2,
9, 11, 10, 8, 6, 5, 7, 3, 2, 1,
10, 11, 5, 9, 6, 8, 2, 3, 1, 7,
11, 10, 5, 6, 8, 9, 3, 7, 2, 1], dtype=int32)
我调试了进入scipy的代码以获取更多详细信息,然后发现.T操作将矩阵A转换为CSC格式矩阵。然后,除过载操作外,A.T将再次转换为CSR格式矩阵,但其索引更改如下:
A.T.toarray():
array([[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.]])
A.T.indices:
array([ 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3,
5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1,
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0,
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11], dtype=int32)
我无法理解的是B.indices,如下所示:
B.toarray()
array([[2., 1., 1., 1., 0., 1., 1., 0., 1., 1., 1., 1.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[1., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 2.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[0., 1., 0., 1., 2., 1., 1., 1., 1., 1., 1., 1.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[0., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.],
[1., 2., 2., 2., 1., 2., 2., 2., 2., 2., 2., 2.]])
B.indices
array([ 8, 9, 11, 6, 3, 10, 5, 1, 2, 0,
4, 0, 7, 3, 11, 6, 8, 5, 10, 9, 2, 1,
0, 3, 8, 7, 11, 6, 9, 5, 1, 10, 2,
4, 0, 1, 2, 10, 9, 11, 5, 7, 6, 8, 3,
5, 10, 6, 3, 11, 8, 7, 1, 9, 4,
4, 0, 1, 7, 2, 3, 9, 8, 10, 11, 6, 5,
4, 0, 1, 2, 7, 3, 10, 9, 11, 8, 5, 6,
4, 1, 2, 10, 11, 5, 8, 6, 3, 9, 7,
4, 0, 2, 1, 7, 10, 3, 5, 9, 11, 6, 8,
4, 0, 1, 2, 3, 7, 5, 6, 8, 10, 11, 9,
4, 0, 7, 1, 3, 2, 8, 6, 9, 5, 11, 10,
4, 0, 1, 2, 7, 3, 9, 8, 6, 5, 10, 11], dtype=int32)
结果B是通过C ++计算的,因此scipy中的_sparsetools.cpython-35m-x86_64-linux-gnu.so库因此无法获取其代码。
这个问题几乎使我发疯。希望你们中的一些可以帮助我。
答案 0 :(得分:0)
如果我从您的A
屏幕上显示A.todense()
:
In [156]: A = np.array([[1., 1., 1., 1., 0., 1., 1., 0., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.],
...: [0., 1., 1., 1., 0., 1., 1., 1., 1., 1., 1., 1.]])
和其中的一个稀疏:
In [159]: M = sparse.csr_matrix(A)
In [160]: M
Out[160]:
<12x12 sparse matrix of type '<class 'numpy.float64'>'
with 120 stored elements in Compressed Sparse Row format>
In [162]: M.indices
Out[162]:
array([ 0, 1, 2, 3, 5, 6, 8, 9, 10, 11, 1, 2, 3, 5, 6, 7, 8,
9, 10, 11, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 5,
6, 7, 8, 9, 10, 11, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 1,
2, 3, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 5, 6, 7, 8, 9,
10, 11, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 5, 6,
7, 8, 9, 10, 11, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 1, 2,
3, 5, 6, 7, 8, 9, 10, 11, 1, 2, 3, 5, 6, 7, 8, 9, 10,
11], dtype=int32)
这些索引与您的索引不同-或相同,但按行排序:
In [164]: for i in range(12):
...: print(M.indices[M.indptr[i]:M.indptr[i+1]])
...:
[ 0 1 2 3 5 6 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 3 4 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
[ 1 2 3 5 6 7 8 9 10 11]
对于其转置的csr
版本:
In [165]: M1 = M.T.tocsr()
In [166]: for i in range(12):
...: print(M1.indices[M1.indptr[i]:M1.indptr[i+1]])
[0]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[4]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
通过切换为具有相同属性的csc
格式来进行移调很快,但是正如您注意到的那样,它已经转换回csr
。
然后取总和:
In [167]: B = M+M.T
In [168]: for i in range(12):
...: print(B.indices[B.indptr[i]:B.indptr[i+1]])
[ 0 1 2 3 5 6 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 1 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
[ 0 1 2 3 4 5 6 7 8 9 10 11]
由于M
索引是按行排序的,因此模式非常明显。
In [172]: M.has_sorted_indices
Out[172]: True
我的版本也是canonical
。
A
的所有行都有10个非零项。 B
有10、11、12;转置为0-2非零填充。
您的A
具有未排序的索引。 A.T.indices
已排序。我想可能会通过将无序B.indices
与A.indices
进行比较来推断出评估方法。但是这值得吗?
===
我使用以下方法重新创建了您的非规范矩阵:
In [186]: altindices = np.array([ 0, 2, 1, 5, 10, 3, 6, 11, 9, 8,
...: 1, 2, 9, 10, 5, 8, 6, 11, 3, 7,
...: 2, 10, 1, 5, 9, 6, 11, 7, 8, 3,
...: 3, 8, 6, 7, 5, 11, 9, 10, 2, 1,
...: 4, 9, 1, 7, 8, 11, 3, 6, 10, 5,
...: 5, 6, 11, 10, 8, 9, 3, 2, 7, 1,
...: 6, 5, 8, 11, 9, 10, 3, 7, 2, 1,
...: 7, 9, 3, 6, 8, 5, 11, 10, 2, 1,
...: 8, 6, 11, 9, 5, 3, 10, 7, 1, 2,
...: 9, 11, 10, 8, 6, 5, 7, 3, 2, 1,
...: 10, 11, 5, 9, 6, 8, 2, 3, 1, 7,
...: 11, 10, 5, 6, 8, 9, 3, 7, 2, 1], dtype='int32')
In [188]: M2 = sparse.csr_matrix((M.data, altindices, M.indptr))
M2.T.indices
与M2.indices
(等效于csc
)相同,但是M2.T.tocsr()
在显示时进行了排序。 B2 = M2+M2.T
的索引与您一样。
如果仅评估一行,我将得到相同的索引,确认我的猜测是它逐行执行求和(如上所述,使用indptr
进行迭代):
In [194]: M2[0,:]+(M2.T)[0,:]
Out[194]:
<1x12 sparse matrix of type '<class 'numpy.float64'>'
with 10 stored elements in Compressed Sparse Row format>
In [195]: _.indices
Out[195]: array([ 8, 9, 11, 6, 3, 10, 5, 1, 2, 0], dtype=int32)