仅使用存储元素的Scipy稀疏矩阵赋值

时间:2016-01-11 10:48:27

标签: python numpy matrix scipy sparse-matrix

我有一个大的稀疏矩阵globalGrid(lil_matrix)和一个较小的矩阵localGrid(coo_matrix)。 localGrid表示globalGrid的一个子集,我想用localGrid更新globalGrid。为此,我使用以下代码(在Python Scipy中):

M=sparse.lil_matrix(2*np.ones([5,5]))
m = sparse.eye(3)

M.todense()
matrix([[ 2.,  2.,  2.,  2.,  2.],
    [ 2.,  2.,  2.,  2.,  2.],
    [ 2.,  2.,  2.,  2.,  2.],
    [ 2.,  2.,  2.,  2.,  2.],
    [ 2.,  2.,  2.,  2.,  2.]])

m.todense()
matrix([[ 1.,  0.,  0.],
    [ 0.,  1.,  0.],
    [ 0.,  0.,  1.]])

其中xLocalGrid和yLocalGrid是localGrid原点相对于globalGrid的偏移量。

问题是localGrid是稀疏的,但零元素也分配给了globalGrid。有没有办法我只能分配存储的元素而不是0元素?

我发现numpy中的掩码数组,但这似乎不适用于稀疏的scipy矩阵。

编辑:在回答下面的评论时,这里有一个例子来说明我的意思:

首先设置矩阵:

M[1:4, 1:4] = m

然后分配:

M.todense()
matrix([[ 2.,  2.,  2.,  2.,  2.],
    [ 2.,  1.,  0.,  0.,  2.],
    [ 2.,  0.,  1.,  0.,  2.],
    [ 2.,  0.,  0.,  1.,  2.],
    [ 2.,  2.,  2.,  2.,  2.]])

现在的结果是:

matrix([[ 2.,  2.,  2.,  2.,  2.],
    [ 2.,  1.,  2.,  2.,  2.],
    [ 2.,  2.,  1.,  2.,  2.],
    [ 2.,  2.,  2.,  1.,  2.],
    [ 2.,  2.,  2.,  2.,  2.]])

我需要的结果是:

select * from mytable
order by 
case 
 when `floor`+0 = 0 then 0 
   else 1
 end , `floor`+0,`floor`

2 个答案:

答案 0 :(得分:0)

该行

  

问题是localGrid是稀疏的,但是非零元素也分配给了globalGrid。有没有办法我只能分配存储的元素而不是0元素?

改为?

  

问题是localGrid是稀疏的,但元素也分配给了globalGrid。有没有办法我只能分配存储的元素而不是0元素?

您的问题不是很清楚,但我猜测是因为globalGrid[a:b, c:d]索引跨越了两个数组中应该为0的值,您担心0&是被复制。

让我们用真正的矩阵来试试。

In [13]: M=sparse.lil_matrix((10,10))
In [14]: m=sparse.eye(3)
In [15]: M[4:7,5:8]=m
In [16]: m
Out[16]: 
<3x3 sparse matrix of type '<class 'numpy.float64'>'
    with 3 stored elements (1 diagonals) in DIAgonal format>
In [17]: M
Out[17]: 
<10x10 sparse matrix of type '<class 'numpy.float64'>'
    with 3 stored elements in LInked List format>
In [18]: M.data
Out[18]: array([[], [], [], [], [1.0], [1.0], [1.0], [], [], []], dtype=object)
In [19]: M.rows
Out[19]: array([[], [], [], [], [5], [6], [7], [], [], []], dtype=object)

M没有任何不必要的0。

如果稀疏矩阵中存在不必要的0,则csr格式的往返应该照顾它们

M.tocsr().tolil()

csr格式也有一个就地.eliminate_zeros()方法。

所以你关注的是过度编写目标数组的非零值。

对于密集数组,使用nonzero(或where)可以解决这个问题:

In [87]: X=np.ones((10,10),int)*2
In [88]: y=np.eye(3)
In [89]: I,J=np.nonzero(y)
In [90]: X[I+3,J+2]=y[I,J]
In [91]: X
Out[91]: 
array([[2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 1, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 1, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 1, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]])

尝试稀疏等价物:

In [92]: M=sparse.lil_matrix(X)
In [93]: M
Out[93]: 
<10x10 sparse matrix of type '<class 'numpy.int32'>'
    with 100 stored elements in LInked List format>
In [94]: m=sparse.coo_matrix(y)
In [95]: m
Out[95]: 
<3x3 sparse matrix of type '<class 'numpy.float64'>'
    with 3 stored elements in COOrdinate format>
In [96]: I,J=np.nonzero(m)
In [97]: I
Out[97]: array([0, 1, 2], dtype=int32)
In [98]: J
Out[98]: array([0, 1, 2], dtype=int32)
In [99]: M[I+3,J+2]=m[I,J]
...
TypeError: 'coo_matrix' object is not subscriptable

我本可以使用稀疏矩阵自己的nonzero

In [106]: I,J=m.nonzero()

对于coo格式,这与

相同
In [109]: I,J=m.row, m.col 

在这种情况下,我还可以使用data属性:

In [100]: M[I+3,J+2]=m.data
In [101]: M.A
Out[101]: 
array([[2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 1, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 1, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 1, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
       [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]], dtype=int32)

m.nonzero的代码可能具有指导意义

    A = self.tocoo()
    nz_mask = A.data != 0
    return (A.row[nz_mask],A.col[nz_mask])

因此,您需要注意确保稀疏矩阵的索引和数据属性匹配。

还要注意哪些稀疏格式允许索引。 lil有助于改变价值观。 csr允许逐个元素索引,但如果您尝试将零值更改为非零(或v.v.),则会引发效率警告。 coo有很好的索引和数据配对,但不允许索引。

另一个微妙的观点:在构建coo时,您可以重复坐标。转换为csr格式时,将这些值相加。但我建议的作业只会使用最后一个值,而不是总和。因此,请务必了解您的local矩阵是如何构建的,并了解它是否是一个“干净”的矩阵。表示数据。

答案 1 :(得分:0)

我找到了一个有效的解决方案。而不是使用赋值,我循环遍历稀疏矩阵中的数据(使用M.data和M.rows)并逐个替换元素。

for idx, row in enumerate(m.rows):
    for idy, col in enumerate(row):
        M[yOffset+col, xOffset+idx] = m.data[idx][idy]

如果没有更简单/更快的方法来实现这个结果,我仍然很好奇。

我执行上述答案:

I,J = m.nonzero()
M[I+yOffset,J+xOffset] = m[I,J]
return M'

然而这稍微慢一些。