2015-12-14 14 views
5

Sto provando a calcolare la media di valori diversi da zero in ogni riga di una matrice di righe sparse. Utilizzando il metodo della media di matrice non lo fa:Media dei valori diversi da zero nella matrice sparsa?

>>> from scipy.sparse import csr_matrix 
>>> a = csr_matrix([[0, 0, 2], [1, 3, 8]]) 
>>> a.mean(axis=1) 
matrix([[ 0.66666667], 
     [ 4.  ]]) 

le seguenti opere, ma è lento per grandi matrici:

>>> import numpy as np 
>>> b = np.zeros(a.shape[0]) 
>>> for i in range(a.shape[0]): 
... b[i] = a.getrow(i).data.mean() 
... 
>>> b 
array([ 2., 4.]) 

Qualcuno potrebbe dirmi se c'è un metodo più veloce?

risposta

4

Questo sembra il problema tipico in cui è possibile utilizzare numpy.bincount. Per questo fatto uso di tre funzioni:

(x,y,z)=scipy.sparse.find(a) 

restituisce righe (x), colonne (y) e valori (z) della matrice sparsa. Per instace, x è array([0, 1, 1, 1].

numpy.bincount(x) restituisce, per ogni numero di riga, quanto meny non zero elemnts hai.

numpy.bincount(x,wights=z) restituisce, per ogni riga, le somme di elementi diversi da zero.

un codice di lavoro finale:

from scipy.sparse import csr_matrix 
a = csr_matrix([[0, 0, 2], [1, 3, 8]]) 

import numpy 
import scipy.sparse 
(x,y,z)=scipy.sparse.find(a) 
countings=numpy.bincount(x) 
sums=numpy.bincount(x,weights=z) 
averages=sums/countings 

print(averages) 

rendimenti:

[ 2. 4.] 
+0

Eccellente, grazie – batsc

5

Con una matrice di formato di CSR, si può fare questo ancora più facilmente:

sums = a.sum(axis=1).A1 
counts = np.diff(a.indptr) 
averages = sums/counts 

Row-somme sono supportato direttamente e la struttura del formato CSR indica la differenza tra i valori successivi nelloL'arraycorrisponde esattamente al numero di elementi diversi da zero in ogni riga.

1

Mi piace sempre sommare i valori su qualsiasi asse a cui sei interessato e dividendo per il totale degli elementi non nulli nella rispettiva riga/colonna.

Come così:

sp_arr = csr_matrix([[0, 0, 2], [1, 3, 8]]) 
col_avg = sp_arr.sum(0)/(sp_arr != 0).sum(0) 
row_avg = sp_arr.sum(1)/(sp_arr != 0).sum(1) 
print(col_avg) 
matrix([[ 1., 3., 5.]]) 
print(row_avg) 
matrix([[ 2.], 
     [ 4.]]) 

Fondamentalmente si sta sommando il valore totale di tutte le voci lungo l'asse determinato e dividendo per la somma dei True voci in cui la matrice = 0 (che è il numero di reale! inserimenti).

Trovo questo approccio meno complicato e più facile rispetto alle altre opzioni.

Problemi correlati