¿Cuál es la forma más eficiente de establecer la fila en ceros para una matriz escasa escasa?

Estoy intentando convertir el siguiente código MATLAB a Python y tengo problemas para encontrar una solución que funcione en un tiempo razonable.

M = diag(sum(a)) - a; where = vertcat(in, out); M(where,:) = 0; M(where,where) = 1; 

Aquí, a es una matriz dispersa y donde es un vector (como in / out). La solución que tengo usando Python es:

 M = scipy.sparse.diags([degs], [0]) - A where = numpy.hstack((inVs, outVs)).astype(int) M = scipy.sparse.lil_matrix(M) M[where, :] = 0 # This is the slowest line M[where, where] = 1 M = scipy.sparse.csc_matrix(M) 

Pero como A es 334863×334863, esto toma como tres minutos. ¡Si alguien tiene alguna sugerencia sobre cómo hacer esto más rápido, por favor contribuya! Para comparación, MATLAB hace este mismo paso de manera imperceptible y rápida.

¡Gracias!

La solución que utilizo para atributos de tareas similares a @seberg y no convierto a formato lil :

 import scipy.sparse import numpy import time def csr_row_set_nz_to_val(csr, row, value=0): """Set all nonzero elements (elements currently in the sparsity pattern) to the given value. Useful to set to 0 mostly. """ if not isinstance(csr, scipy.sparse.csr_matrix): raise ValueError('Matrix given must be of CSR format.') csr.data[csr.indptr[row]:csr.indptr[row+1]] = value def csr_rows_set_nz_to_val(csr, rows, value=0): for row in rows: csr_row_set_nz_to_val(csr, row) if value == 0: csr.eliminate_zeros() 

envuelve tus evaluaciones con tiempo

 def evaluate(size): degs = [1]*size inVs = list(xrange(1, size, size/25)) outVs = list(xrange(5, size, size/25)) where = numpy.hstack((inVs, outVs)).astype(int) start_time = time.time() A = scipy.sparse.csc_matrix((size, size)) M = scipy.sparse.diags([degs], [0]) - A csr_rows_set_nz_to_val(M, where) return time.time()-start_time 

y prueba su rendimiento:

 >>> print 'elapsed %.5f seconds' % evaluate(334863) elapsed 0.53054 seconds 

Una versión ligeramente diferente del enfoque de alko / seberg. Los bucles me parecen molestos, por lo que pasé la mayor parte de esta mañana pensando en una forma de deshacerme de él. Lo siguiente no siempre es más rápido que el otro enfoque. Se realiza mejor cuantas más filas hay que poner a cero y más dispersa la matriz:

 def csr_zero_rows(csr, rows_to_zero): rows, cols = csr.shape mask = np.ones((rows,), dtype=np.bool) mask[rows_to_zero] = False nnz_per_row = np.diff(csr.indptr) mask = np.repeat(mask, nnz_per_row) nnz_per_row[rows_to_zero] = 0 csr.data = csr.data[mask] csr.indices = csr.indices[mask] csr.indptr[1:] = np.cumsum(nnz_per_row) 

Y para probar ambos enfoques:

 rows, cols = 334863, 334863 a = sps.rand(rows, cols, density=0.00001, format='csr') b = a.copy() rows_to_zero = np.random.choice(np.arange(rows), size=10000, replace=False) In [117]: a Out[117]: <334863x334863 sparse matrix of type '' with 1121332 stored elements in Compressed Sparse Row format> In [118]: %timeit -n1 -r1 csr_rows_set_nz_to_val(a, rows_to_zero) 1 loops, best of 1: 75.8 ms per loop In [119]: %timeit -n1 -r1 csr_zero_rows(b, rows_to_zero) 1 loops, best of 1: 32.5 ms per loop 

Y por supuesto:

 np.allclose(a.data, b.data) Out[122]: True np.allclose(a.indices, b.indices) Out[123]: True np.allclose(a.indptr, b.indptr) Out[124]: True