scipy.sparse矩阵:将行的平均值减去非零元素

时间:2016-09-25 09:07:36

标签: python scipy updates sparse-matrix mean

我有一个csr_matrix格式的稀疏矩阵。对于每一行,我需要从非零元素中减去行均值。必须根据行的非零元素的数量(而不是行的长度)计算均值。 我发现了一种使用以下代码计算行均值的快速方法:

# M is a csr_matrix
sums = np.squeeze(np.asarray(M.sum(1)))    # sum of the nonzero elements, for each row
counts = np.diff(M.tocsr().indptr)         # count of the nonzero elements, for each row


# for the i-th row the mean is just sums[i] / float(counts[i]) 

问题是更新部分。我需要一个快速的方法来做到这一点。 实际上我正在做的是将M转换为lil_matrix并以这种方式执行更新:

M = M.tolil()

for i in xrange(len(sums)):
    for j in M.getrow(i).nonzero()[1]:
        M[i, j] -= sums[i] / float(counts[i])

这很慢。有关更快解决方案的任何建议吗?

2 个答案:

答案 0 :(得分:3)

这个很棘手。我想我拥有它。基本思想是我们尝试使用对角线上的平均值来获得对角矩阵,并且使用类似于M的矩阵,但是在M中的非零数据位置处有一个矩阵。然后我们将这些矩阵相乘并从M中减去该乘积。去...

>>> import numpy as np
>>> import scipy.sparse as sp
>>> a = sp.csr_matrix([[1., 0., 2.], [1.,2.,3.]])
>>> a.todense()
matrix([[ 1.,  0.,  2.],
        [ 1.,  2.,  3.]])
>>> tot = np.array(a.sum(axis=1).squeeze())[0]
>>> tot
array([ 3.,  6.])
>>> cts = np.diff(a.indptr)
>>> cts
array([2, 3], dtype=int32)
>>> mu = tot/cts
>>> mu
array([ 1.5,  2. ])
>>> d = sp.diags(mu, 0)
>>> d.todense()
matrix([[ 1.5,  0. ],
        [ 0. ,  2. ]])
>>> b = a.copy()
>>> b.data = np.ones_like(b.data)
>>> b.todense()
matrix([[ 1.,  0.,  1.],
        [ 1.,  1.,  1.]])
>>> (d * b).todense()
matrix([[ 1.5,  0. ,  1.5],
        [ 2. ,  2. ,  2. ]])
>>> (a - d*b).todense()
matrix([[-0.5,  0. ,  0.5],
        [-1. ,  0. ,  1. ]])
祝你好运!希望有所帮助。

答案 1 :(得分:2)

@Dthal's示例开始:

In [92]: a = sparse.csr_matrix([[1.,0,2],[1,2,3]])
In [93]: a.A
Out[93]: 
array([[ 1.,  0.,  2.],
       [ 1.,  2.,  3.]])

In [94]: sums=np.squeeze(a.sum(1).A)
# sums=a.sum(1).A1   # shortcut
In [95]: counts=np.diff(a.tocsr().indptr)
In [96]: means=sums/counts
In [97]: sums
Out[97]: array([ 3.,  6.])
In [98]: counts
Out[98]: array([2, 3], dtype=int32)
In [99]: means
Out[99]: array([ 1.5,  2. ])

repeat让我们复制means,生成一个与矩阵data匹配的数组。

In [100]: mc = np.repeat(means, counts)
In [101]: mc
Out[101]: array([ 1.5,  1.5,  2. ,  2. ,  2. ])

mc@Dthal's (b*d).data相同。

现在只需从data中减去它。

In [102]: a.data -= mc
In [103]: a.A
Out[103]: 
array([[-0.5,  0. ,  0.5],
       [-1. ,  0. ,  1. ]])