2011-12-01 14 views
5

Przetwarzam raczej duże macierze w języku Python/Scipy. Muszę wyodrębnić wiersze z dużej macierzy (która jest ładowana do coo_matrix) i użyć ich jako przekątnych. Obecnie to zrobić w następujący sposób:Tworzenie rzadkiej macierzy diagonalnej z wiersza rzadkiej macierzy

import numpy as np 
from scipy import sparse 

def computation(A): 
    for i in range(A.shape[0]): 
    diag_elems = np.array(A[i,:].todense()) 
    ith_diag = sparse.spdiags(diag_elems,0,A.shape[1],A.shape[1], format = "csc") 
    #... 

#create some random matrix 
A = (sparse.rand(1000,100000,0.02,format="csc")*5).astype(np.ubyte) 
#get timings 
profile.run('computation(A)') 

Co widzę z wyjścia profile jest to, że przez większość czasu jest zużywana przez get_csr_submatrix funkcji podczas wydobywania diag_elems. To sprawia, że ​​myślę, że używam albo nieefektywnej, rzadkiej reprezentacji początkowych danych, albo niewłaściwego sposobu wyodrębniania wiersza z rzadkiej macierzy. Czy możesz zaproponować lepszy sposób wyodrębnienia wiersza z rzadkiej macierzy i przedstawienia go w przekątnej?

EDIT

Poniżej wariant usuwa gardła z ekstrakcji rzędu (Należy zauważyć, że na łatwą zmianę 'csc' do csr nie jest wystarczająca, A[i,:] należy wymienić A.getrow(i) również). Jednak głównym pytaniem jest, jak pominąć materializację (.todense()) i utworzyć przekątną matrycę z rzadkiej reprezentacji wiersza.

import numpy as np 
from scipy import sparse 

def computation(A): 
    for i in range(A.shape[0]): 
    diag_elems = np.array(A.getrow(i).todense()) 
    ith_diag = sparse.spdiags(diag_elems,0,A.shape[1],A.shape[1], format = "csc") 
    #... 

#create some random matrix 
A = (sparse.rand(1000,100000,0.02,format="csr")*5).astype(np.ubyte) 
#get timings 
profile.run('computation(A)') 

Jeśli tworzę przekątnej matrycy od 1-rzędowym CSR matrycy bezpośrednio, w następujący sposób:

diag_elems = A.getrow(i) 
ith_diag = sparse.spdiags(diag_elems,0,A.shape[1],A.shape[1]) 

wtedy mogę ani określić format="csc" argumentu, ani konwertować ith_diags w formacie CSC:

Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/local/lib/python2.6/profile.py", line 70, in run 
    prof = prof.run(statement) 
    File "/usr/local/lib/python2.6/profile.py", line 456, in run 
    return self.runctx(cmd, dict, dict) 
    File "/usr/local/lib/python2.6/profile.py", line 462, in runctx 
    exec cmd in globals, locals 
    File "<string>", line 1, in <module> 
    File "<stdin>", line 4, in computation 
    File "/usr/local/lib/python2.6/site-packages/scipy/sparse/construct.py", line 56, in spdiags 
    return dia_matrix((data, diags), shape=(m,n)).asformat(format) 
    File "/usr/local/lib/python2.6/site-packages/scipy/sparse/base.py", line 211, in asformat 
    return getattr(self,'to' + format)() 
    File "/usr/local/lib/python2.6/site-packages/scipy/sparse/dia.py", line 173, in tocsc 
    return self.tocoo().tocsc() 
    File "/usr/local/lib/python2.6/site-packages/scipy/sparse/coo.py", line 263, in tocsc 
    data = np.empty(self.nnz, dtype=upcast(self.dtype)) 
    File "/usr/local/lib/python2.6/site-packages/scipy/sparse/sputils.py", line 47, in upcast 
    raise TypeError,'no supported conversion for types: %s' % args 
TypeError: no supported conversion for types: object` 
+1

wypróbowałeś 'format =" csr "' zamiast? – cyborg

+0

Z "csr" dla danych początkowych i 'A [i,:]' zastąpione 'A.getrow (i)' osiągnąłem znaczne przyspieszenie. Ale to, czego szukam, to pominięcie materializowania tworzenia się diagonalnej macierzy diagonalnej. Jakieś pomysły? – savenkov

Odpowiedz

3

Oto, co wymyśliłem:

def computation(A): 
    for i in range(A.shape[0]): 
     idx_begin = A.indptr[i] 
     idx_end = A.indptr[i+1] 
     row_nnz = idx_end - idx_begin 
     diag_elems = A.data[idx_begin:idx_end] 
     diag_indices = A.indices[idx_begin:idx_end] 
     ith_diag = sparse.csc_matrix((diag_elems, (diag_indices, diag_indices)),shape=(A.shape[1], A.shape[1])) 
     ith_diag.eliminate_zeros() 

Profiler w języku Python powiedział 1.464 sekundy w porównaniu do 5.574 sekundy wcześniej. Korzysta z podstawowych gęstych tablic (indptr, indeksy, dane), które definiują rzadkie macierze. Oto mój kurs zderzeniowy: A.indptr [i]: A.indptr [i + 1] określa, które elementy w gęstych tablicach odpowiadają niezerowym wartościom w wierszu i. A.data to gęsta tablica 1d niezerowa wartości A i A.indptr to kolumna, w której te wartości idą.

Zrobiłbym więcej testów, aby upewnić się, że robi to samo co poprzednio. Sprawdziłem tylko kilka przypadków.

+0

Kevin, świetnie! – savenkov

+0

BTW, row_nnz jest nieużywany – savenkov

Powiązane problemy