2016-09-25 3 views
2

Ich habe eine dünne Matrix in csr_matrix Format. Für jede Zeile muss ich den Zeilenmittelwert von den Nicht-Null-Elementen subtrahieren. Die Mittelwerte müssen anhand der Anzahl der von Null verschiedenen Elemente der Zeile berechnet werden (anstelle der Länge der Zeile). ich einen schnellen Weg gefunden, um die Zeile zu berechnen bedeutet, mit dem folgenden Code:scipy.sparse Matrix: subtrahieren Zeile Mittelwert zu ungleich Null Elemente

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

Das Problem der Teil-Updates ist. Ich brauche einen schnellen Weg, dies zu tun. Eigentlich, was ich tue, ist M zu einem lil_matrix und führen Sie die Updates auf diese Weise zu transformieren:

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

, die langsam ist. Irgendwelche Vorschläge für eine schnellere Lösung?

+0

Ich würde versuchen, die Zeile zu replizieren bedeutet 'np.repeat' und' counts' verwenden und Unter, die direkt von 'M.data' Array. – hpaulj

Antwort

2

Dieser ist knifflig. Ich denke ich habe es. Die Grundidee ist, dass wir versuchen, eine diagonale Matrix mit den Mitteln auf der Diagonalen zu erhalten, und eine Matrix, die wie M ist, aber solche an den Datenpositionen ungleich Null in M ​​hat. Dann multiplizieren wir diese und subtrahieren das Produkt von M. Hier geht ...

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

Viel Glück! Ich hoffe, das hilft.

+0

Ja, ich dachte an die gleiche Sache. Vielen Dank! – revy

2

mit @Dthal's Probe Beginn:

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 lässt uns die means replizieren, ein Array erzeugen, die die Matrix data in der Größe übereinstimmt.

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

Diese mc ist die gleiche wie @Dthal's(b*d).data.

Nun einfach von data subtrahieren.

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