python - scipy.sparse.coo_matrix 如何快速找到全零列,填充 1 并标准化

标签 python numpy scipy linear-algebra sparse-matrix

对于一个矩阵,我想找到全为零的列并用1填充,然后按列对矩阵进行归一化。我知道如何使用 np.arrays 做到这一点

[[0 0 0 0 0]
 [0 0 1 0 0]
 [1 0 0 1 0]
 [0 0 0 0 1]
 [1 0 0 0 0]]      
     |
     V
[[0 1 0 0 0]
 [0 1 1 0 0]
 [1 1 0 1 0]    
 [0 1 0 0 1]
 [1 1 0 0 0]]
     |
     V
[[0   0.2 0 0 0]
 [0   0.2 1 0 0]
 [0.5 0.2 0 1 0]   
 [0   0.2 0 0 1]
 [0.5 0.2 0 0 0]]

但是,当矩阵采用 scipy.sparse.coo.coo_matrix 形式时,我该如何做同样的事情,而不将其转换回 np.arrays。我怎样才能实现同样的目标?

最佳答案

使用 lil 格式,并且使用行而不是列,这会容易得多:

In [1]: from scipy import sparse
In [2]: A=np.array([[0,0,0,0,0],[0,0,1,0,0],[1,0,0,1,0],[0,0,0,0,1],[1,0,0,0,0]])
In [3]: A
Out[3]: 
array([[0, 0, 0, 0, 0],
       [0, 0, 1, 0, 0],
       [1, 0, 0, 1, 0],
       [0, 0, 0, 0, 1],
       [1, 0, 0, 0, 0]])
In [4]: At=A.T                # switch to work with rows

In [5]: M=sparse.lil_matrix(At)

现在很明显哪一行全为零

In [6]: M.data
Out[6]: array([[1, 1], [], [1], [1], [1]], dtype=object)
In [7]: M.rows
Out[7]: array([[2, 4], [], [1], [2], [3]], dtype=object)

lil 格式允许我们填充该行:

In [8]: M.data[1]=[1,1,1,1,1]
In [9]: M.rows[1]=[0,1,2,3,4]
In [10]: M.A
Out[10]: 
array([[0, 0, 1, 0, 1],
       [1, 1, 1, 1, 1],
       [0, 1, 0, 0, 0],
       [0, 0, 1, 0, 0],
       [0, 0, 0, 1, 0]], dtype=int32)

我也可以使用M[1,:]=np.ones(5,int)

coo 格式非常适合从 data/row/col 数组创建数组,但不实现索引或数学。为此,必须将其转换为csrcsc 用于面向列的内容。

我填写的行在 csr 格式中并不那么明显:

In [14]: Mc=M.tocsr()
In [15]: Mc.data
Out[15]: array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1], dtype=int32)
In [16]: Mc.indices
Out[16]: array([2, 4, 0, 1, 2, 3, 4, 1, 2, 3], dtype=int32)
In [17]: Mc.indptr
Out[17]: array([ 0,  2,  7,  8,  9, 10], dtype=int32)

另一方面,这种格式的规范化可能更容易。

In [18]: Mc.sum(axis=1)
Out[18]: 
matrix([[2],
        [5],
        [1],
        [1],
        [1]], dtype=int32)
In [19]: Mc/Mc.sum(axis=1)
Out[19]: 
matrix([[ 0. ,  0. ,  0.5,  0. ,  0.5],
        [ 0.2,  0.2,  0.2,  0.2,  0.2],
        [ 0. ,  1. ,  0. ,  0. ,  0. ],
        [ 0. ,  0. ,  1. ,  0. ,  0. ],
        [ 0. ,  0. ,  0. ,  1. ,  0. ]])

请注意,它将稀疏矩阵转换为稠密矩阵。 是稠密的,涉及稀疏和稠密的数学通常会产生稠密。

我必须使用更全面的计算来保持稀疏状态:

In [27]: Mc.multiply(sparse.csr_matrix(1/Mc.sum(axis=1)))
Out[27]: 
<5x5 sparse matrix of type '<class 'numpy.float64'>'
    with 10 stored elements in Compressed Sparse Row format>

这是使用 csc 格式执行此操作的方法(在 A 上)

In [40]: Ms=sparse.csc_matrix(A)
In [41]: Ms.sum(axis=0)
Out[41]: matrix([[2, 0, 1, 1, 1]], dtype=int32)

使用 sum 查找全零列。显然,如果列具有负值并且总和为 0,这可能是错误的。如果这是一个问题,我可以看到制作矩阵的副本,并将所有 data 值替换为 1。

In [43]: Ms[:,1]=np.ones(5,int)[:,None]
/usr/lib/python3/dist-packages/scipy/sparse/compressed.py:730: SparseEfficiencyWarning: Changing the sparsity structure of a csc_matrix is expensive. lil_matrix is more efficient.
  SparseEfficiencyWarning)
In [44]: Ms.A
Out[44]: 
array([[0, 1, 0, 0, 0],
       [0, 1, 1, 0, 0],
       [1, 1, 0, 1, 0],
       [0, 1, 0, 0, 1],
       [1, 1, 0, 0, 0]])

如果您重复进行此类更改,则警告会更重要。请注意,我必须调整 LHS 数组的尺寸。根据全零列的数量,此操作可以显着改变矩阵的稀疏性。

==================

我可以使用以下方法搜索 coo 格式的 col 中的缺失值:

In [69]: Mo=sparse.coo_matrix(A)
In [70]: Mo.col
Out[70]: array([2, 0, 3, 4, 0], dtype=int32)

In [71]: Mo.col==np.arange(Mo.shape[1])[:,None]
Out[71]: 
array([[False,  True, False, False,  True],
       [False, False, False, False, False],
       [ True, False, False, False, False],
       [False, False,  True, False, False],
       [False, False, False,  True, False]], dtype=bool)

In [72]: idx = np.nonzero(~(Mo.col==np.arange(Mo.shape[1])[:,None]).any(axis=1))[0]
In [73]: idx
Out[73]: array([1], dtype=int32)

然后我可以在此 idx 处添加一列 1:

In [75]: N=Mo.shape[0]
In [76]: data = np.concatenate([Mo.data, np.ones(N,int)])
In [77]: row = np.concatenate([Mo.row, np.arange(N)])
In [78]: col = np.concatenate([Mo.col, np.ones(N,int)*idx])
In [79]: Mo1 = sparse.coo_matrix((data,(row, col)), shape=Mo.shape)
In [80]: Mo1.A
Out[80]: 
array([[0, 1, 0, 0, 0],
       [0, 1, 1, 0, 0],
       [1, 1, 0, 1, 0],
       [0, 1, 0, 0, 1],
       [1, 1, 0, 0, 0]])

正如所写,它仅适用于一列,但它可以推广到几列。我还创建了一个新矩阵,而不是更新 Mo。但这个就地似乎也有效:

Mo.data,Mo.col,Mo.row = data,col,row

规范化仍然需要 csr 转换,尽管我认为 sparse 可以为您隐藏它。

In [87]: Mo1/Mo1.sum(axis=0)
Out[87]: 
matrix([[ 0. ,  0.2,  0. ,  0. ,  0. ],
        [ 0. ,  0.2,  1. ,  0. ,  0. ],
        [ 0.5,  0.2,  0. ,  1. ,  0. ],
        [ 0. ,  0.2,  0. ,  0. ,  1. ],
        [ 0.5,  0.2,  0. ,  0. ,  0. ]])

即使我采取额外的工作来维护稀疏性,我仍然得到一个 csr 矩阵:

In [89]: Mo1.multiply(sparse.coo_matrix(1/Mo1.sum(axis=0)))
Out[89]: 
<5x5 sparse matrix of type '<class 'numpy.float64'>'
    with 10 stored elements in Compressed Sparse Row format>

查看

Find all-zero columns in pandas sparse matrix

了解查找 0 列的更多方法。事实证明,对于大型 MoMo.col==np.arange(Mo.shape[1])[:,None] 速度太慢。使用 np.in1d 进行测试要好得多。

1 - np.in1d(np.arange(Mo.shape[1]),Mo.col)

关于python - scipy.sparse.coo_matrix 如何快速找到全零列,填充 1 并标准化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39683931/

相关文章:

python - sys.intern() 是用于每次查找,还是仅在第一次创建字符串时使用? (Python后续)

python - 将彩虹矩阵转换为 RBG 并另存为 PNG

python - 为什么Python共享内存需要副本?

python - 使用 scipy 的 solve_bvp 求解具有两个边界条件的一阶 BVP

python - 如何使用 Python 对原始信号应用 FFT

Python C-Api 线程问题

python - Matplotlib:在线边缘上绘制标记

python - 如何从 python/scipy/numpy 等中的阶跃函数中采样?

python-3.x - 将一维数组转换为 Numpy 中的行或列向量

python - 用 0 到 1 之间的值替换 numpy 数组元素