2012-08-26 32 views
7

Supongamos que tengo una matriz en el formato CSR, ¿cuál es la forma más eficiente de establecer una fila (o filas) en ceros?scipy.sparse: Establecer fila a ceros

El siguiente código se ejecuta muy lentamente:

A = A.tolil() 
A[indices, :] = 0 
A = A.tocsr() 

tuve que convertir a scipy.sparse.lil_matrix porque el formato de la RSE parece apoyar la indexación ni lujoso, ni el establecimiento de valores a rodajas.

+0

Bueno, acabo intentaron una '[A .__ SetItem __ ((i, j), 0) para i en índices para j en rango (A.shape [1])] 'y' SciPy' me dijeron que 'SparseEfficiencyWarning: cambiar la estructura de dispersión de una matriz csr_matrix es costoso. lil_matrix es más eficiente. ... –

+0

no tiene idea si scipy tiene algún soporte para él, pero como es una matriz de CSR, esto se puede manejar eficientemente (al menos a mano). Una pregunta es, ¿quieres cambiar el patrón de dispersión, o esos 0 deben ser numéricamente 0? – seberg

+0

No estoy seguro de qué se entiende por patrón de dispersión.Procuro resolver un sistema de ecuaciones usando la función scipy.sparse.linalg.spsolve. Espero que esto establezca la necesidad de cambiar el patrón de dispersión, o la falta de él. –

Respuesta

5

supongo SciPy simplemente no ponerlo en práctica, pero el formato RSE apoyaría esta bastante bien, por favor leer el artículo de Wikipedia sobre "matriz dispersa" sobre lo indptr, etc., son:

# A.indptr is an array, one for each row (+1 for the nnz): 

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 

# Now you can just do: 
for row in indices: 
    csr_row_set_nz_to_val(A, row, 0) 

# And to remove zeros from the sparsity pattern: 
A.eliminate_zeros() 

Por supuesto esto elimina los 0 que se establecieron desde otro lugar con eliminate_zeros del patrón de dispersión. Si quieres hacer eso (en este punto) depende de lo que estás haciendo realmente, es decir. la eliminación puede tener sentido para retrasar hasta que todos los demás cálculos que podrían agregar nuevos ceros también se realicen, o en algunos casos puede tener 0 valores, que desea cambiar nuevamente más tarde, por lo que sería muy malo eliminarlos.

En principio podría cortocircuitar el eliminate_zeros y el prune, pero eso debería ser muy complicado, y podría ser incluso más lento (porque no lo hará en C).


Los detalles sobre eliminiate_zeros (y ciruela)

La matriz dispersa, generalmente no guardar elementos cero, pero sólo tiendas donde los elementos no nulos son (más o menos y con varios métodos). eliminate_zeros elimina todos los ceros en su matriz del patrón de dispersión (es decir, no hay ningún valor almacenado para esa posición, cuando antes de allí era un vlaue almacenado, pero era 0). Eliminar es malo si quiere cambiar un 0 a un valor diferente más tarde, de lo contrario, ahorra espacio.

Prune simplemente encogerá las matrices de datos almacenadas cuando sean más largas de lo necesario. Tenga en cuenta que, aunque tenía A.prune() por primera vez, A.eliminiate_zeros() ya incluye ciruela pasa.

+0

¡Gracias! ¡Eso aceleró las cosas considerablemente! Me gustaría saber qué hacen los delete_zeros y las declaraciones de prune. –

+0

Agregó una oración (con suerte comprensible). Tenga en cuenta que 'prune()' no era necesario, 'eliminate_zeros' ya llama' prune' – seberg

0

Actualiza a la última versión de scipy. Es compatible con la indexación de lujo.

0

Puede usar el producto matriz de puntos para lograr esa puesta a cero. Dado que la matriz que usaremos es muy dispersa (diagonal con ceros para las filas/columnas a las cuales debemos poner a cero), la multiplicación debería ser eficiente.

Usted necesitará una de las siguientes funciones: ejemplo

import scipy.sparse 

def zero_rows(M, rows): 
    diag = scipy.sparse.eye(M.shape[0]).tolil() 
    for r in rows: 
     diag[r, r] = 0 
    return diag.dot(M) 

def zero_columns(M, columns): 
    diag = scipy.sparse.eye(M.shape[1]).tolil() 
    for c in columns: 
     diag[c, c] = 0 
    return M.dot(diag) 

Uso:

>>> A = scipy.sparse.csr_matrix([[1,0,3,4], [5,6,0,8], [9,10,11,0]]) 
>>> A 
<3x4 sparse matrix of type '<class 'numpy.int64'>' 
     with 9 stored elements in Compressed Sparse Row format> 
>>> A.toarray() 
array([[ 1, 0, 3, 4], 
     [ 5, 6, 0, 8], 
     [ 9, 10, 11, 0]], dtype=int64) 

>>> B = zero_rows(A, [1]) 
>>> B 
<3x4 sparse matrix of type '<class 'numpy.float64'>' 
     with 6 stored elements in Compressed Sparse Row format> 
>>> B.toarray() 
array([[ 1., 0., 3., 4.], 
     [ 0., 0., 0., 0.], 
     [ 9., 10., 11., 0.]]) 

>>> C = zero_columns(A, [1, 3]) 
>>> C 
<3x4 sparse matrix of type '<class 'numpy.float64'>' 
     with 5 stored elements in Compressed Sparse Row format> 
>>> C.toarray() 
array([[ 1., 0., 3., 0.], 
     [ 5., 0., 0., 0.], 
     [ 9., 0., 11., 0.]]) 
Cuestiones relacionadas