2013-03-01 8 views
5

Ho array grandi ma sparsi e voglio riorganizzarli scambiando righe e colonne. Qual è un buon modo per farlo in scipy.sparse?Riorganizzare gli array sparsi scambiando righe e colonne

Alcuni problemi

  • Io non credo che matrici di permutazione sono adatti per questo compito, come a loro piace in modo casuale cambiano la struttura scarsità. E una manipolazione "moltiplica" sempre tutte le colonne o le righe, anche se sono necessari solo pochi swap.

  • Qual è la migliore rappresentazione di matrice sparsa in scipy.sparse per questa attività?

  • I suggerimenti per l'implementazione sono molto graditi.

Ho etichettato questo con Matlab così, dal momento che questa domanda potrebbe trovare una risposta che non è necessariamente scipy specifica.

+0

Ho bisogno di questo per una particolare implementazione. Tuttavia, come mi ha fatto notare un collega, in generale, non si farebbero permutazioni su una matrice sparsa. Una matrice sparsa 'A' viene generalmente utilizzata come una mappa lineare' y = Ax ', ad es. in solutori iterativi. Quindi questo scambio si realizza meglio scrivendo un wrapper attorno a 'A', scambiando le voci del vettore di input x (questo è lo scambio di colonne in' A') o le voci di 'y' (questo è lo scambio di righe). – Jan

risposta

4

CSC mantiene un elenco degli indici di riga di tutte le voci diverse da zero, il formato CSR mantiene un elenco degli indici delle colonne di tutte le voci diverse da zero. Penso che si possa approfittare di questo per scambiare le cose intorno come segue, e penso che non ci dovrebbero essere effetti collaterali ad esso:

def swap_rows(mat, a, b) : 
    mat_csc = scipy.sparse.csc_matrix(mat) 
    a_idx = np.where(mat_csc.indices == a) 
    b_idx = np.where(mat_csc.indices == b) 
    mat_csc.indices[a_idx] = b 
    mat_csc.indices[b_idx] = a 
    return mat_csc.asformat(mat.format) 

def swap_cols(mat, a, b) : 
    mat_csr = scipy.sparse.csr_matrix(mat) 
    a_idx = np.where(mat_csr.indices == a) 
    b_idx = np.where(mat_csr.indices == b) 
    mat_csr.indices[a_idx] = b 
    mat_csr.indices[b_idx] = a 
    return mat_csr.asformat(mat.format) 

Si potrebbe ora fare qualcosa di simile:

>>> mat = np.zeros((5,5)) 
>>> mat[[1, 2, 3, 3], [0, 2, 2, 4]] = 1 
>>> mat = scipy.sparse.lil_matrix(mat) 
>>> mat.todense() 
matrix([[ 0., 0., 0., 0., 0.], 
     [ 1., 0., 0., 0., 0.], 
     [ 0., 0., 1., 0., 0.], 
     [ 0., 0., 1., 0., 1.], 
     [ 0., 0., 0., 0., 0.]]) 
>>> swap_rows(mat, 1, 3) 
<5x5 sparse matrix of type '<type 'numpy.float64'>' 
    with 4 stored elements in LInked List format> 
>>> swap_rows(mat, 1, 3).todense() 
matrix([[ 0., 0., 0., 0., 0.], 
     [ 0., 0., 1., 0., 1.], 
     [ 0., 0., 1., 0., 0.], 
     [ 1., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 0.]]) 
>>> swap_cols(mat, 0, 4) 
<5x5 sparse matrix of type '<type 'numpy.float64'>' 
    with 4 stored elements in LInked List format> 
>>> swap_cols(mat, 0, 4).todense() 
matrix([[ 0., 0., 0., 0., 0.], 
     [ 0., 0., 0., 0., 1.], 
     [ 0., 0., 1., 0., 0.], 
     [ 1., 0., 1., 0., 0.], 
     [ 0., 0., 0., 0., 0.]]) 

Ho usato una matrice LIL per mostrare come è possibile conservare il tipo di output. Nella tua applicazione probabilmente vuoi già essere in formato CSC o CSR e selezionare se scambiare prima le righe o le colonne in base ad esso, per ridurre al minimo le conversioni.

+0

Grazie @Jaime, questo sembra essere quello che stavo cercando. E mostra che dovrei avere più familiarità con i formati sparsi. – Jan

+0

@Jan Potresti voler testarlo un po 'di più, penso che gli esempi sopra funzionino perché tutte le voci diverse da zero sono le stesse. Non ho tempo adesso, ma lo esaminerò più dettagliatamente in seguito. C'è un altro array, 'mat.indptr', che potrebbe aver bisogno di alcune modifiche. [L'articolo wikipedia sul formato sparse di Yale] (http://en.wikipedia.org/wiki/Sparse_matrix#Yale_format) ha tutte le informazioni necessarie, nel caso tu voglia provarlo tu stesso! – Jaime

+0

Lo metterò alla prova e ti faccio sapere ... Grazie per la fonte. – Jan

0

In Matlab si può solo indicizzare le colonne e le righe il modo che ti piace:

Matrix = speye(10); 
mycolumnorder = [1 2 3 4 5 6 10 9 8 7]; 
myroworder = [4 3 2 1 5 6 7 8 9 10]; 
Myorderedmatrix = Matrix(myroworder,mycolumnorder); 

penso che questo conserva scarsità ... Non so se SciPy ...

formato