我有一个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])
这很慢。有关更快解决方案的任何建议吗?
答案 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. ]])