2016-09-25 128 views
2

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

# 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

我试图复制行意味着使用'np.repeat'和'counts',并直接从'M.data'数组。 – hpaulj

回答

2

这是一个棘手。我想我已经拥有了。其基本思想是,我们试图用对角线上的平均值来获得一个对角矩阵,以及一个像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. ]]) 

祝你好运!希望有所帮助。

+0

是的,我在想同样的事情。谢谢! – revy

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. ]])