我如何使用scipy.sparse.dia_matrix记住一个稀疏的带状矩阵,为它提供不同尺寸的数组(对角线)?

时间:2018-10-29 14:09:03

标签: python python-3.x scipy

我想用scipy.sparse.dia_matrix记住一个五对角正方形矩阵。第一个和最后一个对角线距离主要对角线较远,因此它们包含的元素少于主要对角线。似乎dia_matrix仅接受与主对角线长度相同的对角线。我想节省内存,并给它不同长度的数组。可能吗?下面是一个示例(三对角线):

diag1 = [88,99]
main_diag = [1,2,3,4]
diag2 = [ 101,202]



A = [ 1,   0, 88, 0
      0,   2,  0, 99
      101, 0,  3, 0
      0,  202, 0, 4 ] 
A = scipy.sparse.dia_matrix(([[diag1],[main_diag],[diag2]],offsets), shape= (4,4))

但是它给了我一个错误,除非我不将对角线记为:

diag1 = [0,0,88,99]
main_diag = [1,2,3,4]
diag2 = [ 101,202,0,0]

但是这种方式不能节省内存。

1 个答案:

答案 0 :(得分:0)

您的稠密矩阵(为什么不兼容此cut-n-paste?)

In [589]: A = np.array([[ 1,   0, 88, 0],
     ...:       [0,   2,  0, 99],
     ...:       [101, 0,  3, 0],
     ...:       [0,  202, 0, 4] ])
     ...:       
In [590]: A
Out[590]: 
array([[  1,   0,  88,   0],
       [  0,   2,   0,  99],
       [101,   0,   3,   0],
       [  0, 202,   0,   4]])

我们可以直接从dia制作A矩阵:

In [591]: M = sparse.dia_matrix(A)
In [592]: M
Out[592]: 
<4x4 sparse matrix of type '<class 'numpy.int64'>'
    with 8 stored elements (3 diagonals) in DIAgonal format>

dia格式存储的是两个数组中的值,分别是2d data和1d offsets

In [593]: M.data
Out[593]: 
array([[101, 202,   0,   0],
       [  1,   2,   3,   4],
       [  0,   0,  88,  99]])
In [594]: M.offsets
Out[594]: array([-2,  0,  2], dtype=int32)

我们可以使用sparse.diags函数从您的3个对角线构造dia矩阵:

In [605]: M1 = sparse.diags([diag1, main_diag, diag2],[2,0,-2], dtype=int)
In [606]: M1
Out[606]: 
<4x4 sparse matrix of type '<class 'numpy.int64'>'
    with 8 stored elements (3 diagonals) in DIAgonal format>
In [607]: M1.A
Out[607]: 
array([[  1,   0,  88,   0],
       [  0,   2,   0,  99],
       [101,   0,   3,   0],
       [  0, 202,   0,   4]])
In [608]: M1.data
Out[608]: 
array([[  0,   0,  88,  99],
       [  1,   2,   3,   4],
       [101, 202,   0,   0]])

但是底层存储是相同的。

我不知道dia_matrix为什么使用这种格式的详细信息。我怀疑这与存储和处理成本的平衡有关。要将data存储为2d数组,它必须具有某种填充。否则,您将使用[diag1, main_diag, diag2]中的列表列表(或数组/列表的对象数组)。是否使用更多或更少的内存可能取决于矩阵的大小以及offsets的距离。

lil格式,同一矩阵存储为2个列表数组:

In [611]: M.tolil().data
Out[611]: 
array([list([1, 88]), list([2, 99]), list([101, 3]), list([202, 4])],
      dtype=object)
In [612]: M.tolil().rows
Out[612]: 
array([list([0, 2]), list([1, 3]), list([0, 2]), list([1, 3])],
      dtype=object)

coo中的

In [615]: M.tocoo().data
Out[615]: array([101, 202,   1,   2,   3,   4,  88,  99])
In [616]: M.tocoo().row
Out[616]: array([2, 3, 0, 1, 2, 3, 0, 1], dtype=int32)
In [617]: M.tocoo().col
Out[617]: array([0, 1, 0, 1, 2, 3, 2, 3], dtype=int32)

csr被广泛用于计算,它压缩row数组。

如果您以密集形式进行所有计算,则可能需要根据以下内容构造A

np.diag(main_diag,0)+np.diag(diag1,2)+np.diag(diag2,-2)

将此与sparse中介方法进行比较:

In [623]: timeit np.diag(main_diag,0)+np.diag(diag1,2)+np.diag(diag2,-2)
27.5 µs ± 1.28 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [624]: timeit sparse.diags([diag1, main_diag, diag2],[2,0,-2], dtype=int).A
288 µs ± 13 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)