Ho una raccolta di O (N) NxN scipy.sparse.csr_matrix
e ciascuna matrice sparsa è nell'ordine di N elementi impostati. Voglio aggiungere tutte queste matrici insieme per ottenere un normale array numpy NxN. (N è dell'ordine di 1000). La disposizione di elementi diversi da zero all'interno delle matrici è tale che la somma risultante non è certamente sparsa (praticamente nessun elemento a zero rimane in effetti).Accumulo efficiente di una raccolta di matrici scarse spettrali
Al momento mi sto solo facendo
reduce(lambda x,y: x+y,[m.toarray() for m in my_sparse_matrices])
che funziona, ma è un po 'lento: naturalmente l'enorme quantità di elaborazione inutile di zeri che sta andando in là è assolutamente orribile.
C'è un modo migliore? Non c'è niente di ovvio per me nello docs.
Aggiornamento: come suggerito dall'utente545424, ho provato lo schema alternativo di sommare le matrici sparse e anche di sommare matrici sparse su una matrice densa. Il codice seguente mostra tutti gli approcci per l'esecuzione in tempi paragonabili (Python 2.6.6 su amd64 Debian/Squeeze, su un i7 quad-core)
import numpy as np
import numpy.random
import scipy
import scipy.sparse
import time
N=768
S=768
D=3
def mkrandomsparse():
m=np.zeros((S,S),dtype=np.float32)
r=np.random.random_integers(0,S-1,D*S)
c=np.random.random_integers(0,S-1,D*S)
for e in zip(r,c):
m[e[0],e[1]]=1.0
return scipy.sparse.csr_matrix(m)
M=[mkrandomsparse() for i in xrange(N)]
def plus_dense():
return reduce(lambda x,y: x+y,[m.toarray() for m in M])
def plus_sparse():
return reduce(lambda x,y: x+y,M).toarray()
def sum_dense():
return sum([m.toarray() for m in M])
def sum_sparse():
return sum(M[1:],M[0]).toarray()
def sum_combo(): # Sum the sparse matrices 'onto' a dense matrix?
return sum(M,np.zeros((S,S),dtype=np.float32))
def benchmark(fn):
t0=time.time()
fn()
t1=time.time()
print "{0:16}: {1:.3f}s".format(fn.__name__,t1-t0)
for i in xrange(4):
benchmark(plus_dense)
benchmark(plus_sparse)
benchmark(sum_dense)
benchmark(sum_sparse)
benchmark(sum_combo)
print
e disconnette
plus_dense : 1.368s
plus_sparse : 1.405s
sum_dense : 1.368s
sum_sparse : 1.406s
sum_combo : 1.039s
anche se è possibile ottenere uno approccio o l'altro per uscire avanti di un fattore di circa 2 facendo confusione con i parametri N, S, D ... ma nulla di simile all'ordine di grandezza che si spera di vedere dal considerare il numero di zero aggiunge che dovrebbe essere possibile saltare.
Ah, eccellente! Questo è il tipo di algoritmo efficiente che mi aspetterei; solo un peccato che non sembra essere già fornito come un "builtin" ancora più efficiente. Proverò presto ... – timday
Sì, dipende un po 'dalla densità ma il miglioramento della velocità x10 è tipico per il tipo di numeri a cui sono interessato. – timday
Incredibile. Ho appena applicato questo stesso pattern in alcuni altri punti in cui ho interazioni sparse-denso - tipicamente cose di tipo puntino - e ottenendo sempre sostanziali speed-up (x2-x3). – timday