2017-01-06 31 views
5

Mam dwie "scipy_sparse_csr_matrix" a "i scipy_sparse_csr_matrix (boolean)" maska ​​"i chcę ustawić elementy" a "na zero, gdzie element maski jest prawdziwy.Wydajny sposób ustawiania elementów na zero, gdzie maska ​​jest True na scipy rzadkiej macierzy

np

>>>a 
<3x3 sparse matrix of type '<type 'numpy.int32'>' 
    with 4 stored elements in Compressed Sparse Row format> 
>>>a.todense() 
matrix([[0, 0, 3], 
     [0, 1, 5], 
     [7, 0, 0]]) 

>>>mask 
<3x3 sparse matrix of type '<type 'numpy.bool_'>' 
    with 4 stored elements in Compressed Sparse Row format> 
>>>mask.todense() 
matrix([[ True, False, True], 
     [False, False, True], 
     [False, True, False]], dtype=bool) 

Następnie chcę uzyskać następujący wynik.

>>>result 
<3x3 sparse matrix of type '<type 'numpy.int32'>' 
    with 2 stored elements in Compressed Sparse Row format> 
>>>result.todense() 
matrix([[0, 0, 0], 
     [0, 1, 0], 
     [7, 0, 0]]) 

mogę to zrobić przez działania jak

result = a - a.multiply(mask) 

lub

a -= a.multiply(mask) #I don't care either in-place or copy. 

Ale myślę, że powyższe działania są nieskuteczne. Ponieważ rzeczywisty kształt "a" i "maski" wynosi 67 108 864 × 2 000 000, operacje te wymagają kilku sekund na serwerze o wysokiej specyfikacji (64-rdzeniowy procesor Xeon, 512 GB pamięci). Na przykład "a" zawiera około 30 000 000 niezerowych elementów, a "maska" zawiera około 1 800 000 niezerowych (prawdziwych) elementów, a następnie wykonanie tej operacji zajmuje około 2 sekund.

Czy jest to skuteczniejszy sposób?

Warunki są poniżej.

  1. a.getnnz()! = Mask.getnnz()
  2. a.shape = mask.shape

Dzięki!

Inny sposób (próbowałem)

a.data*=~np.array(mask[a.astype(np.bool)]).flatten();a.eliminate_zeros() #This takes twice the time longer than above method. 
+0

Jak porównać 'nnz' z' a' i 'mask'? Poza tym nie być tym samym. Czy oba są równie skąpe? – hpaulj

+0

Dziękuję za odpowiedź, @hpaulj! Przepraszam, że cię zmyliłem. Warunek 1 oznacza tylko "Liczba niezerowych (fałszywych) elementów maski różni się od liczby elementów a.". – hiroto1228

Odpowiedz

0

Moje pierwsze wrażenie jest takie, że to mnożenie i odejmowanie podejście jest uzasadnione jeden. Dość często kod sparse implementuje operacje jako swego rodzaju mnożenie, nawet jeśli gęste odpowiedniki używają bardziej bezpośrednich metod. Rozproszona suma w wierszach lub kolumnach wykorzystuje mnożenie macierzy z odpowiednią macierzą wiersza lub kolumny równą 1s. Nawet indeksowanie wiersza lub kolumny wykorzystuje mnożenie macierzy (przynajmniej w formacie csr).

Czasami możemy poprawić działanie, pracując bezpośrednio z atrybutami macierzy (data, indices, indptr). Ale to wymaga dużo więcej przemyśleń i eksperymentów.

Dla gęstych macierzach moja pierwsza próba byłaby

In [611]: a.A*~(mask.A) 
Out[611]: 
array([[0, 0, 0], 
     [0, 1, 0], 
     [7, 0, 0]], dtype=int32) 

Ale nie ma bezpośredni sposób robienia not do rozrzedzony matrycy. Jeśli mask był rzeczywiście rzadki, nie byłoby go ~mask. W przykładzie mask ma 4 Prawdziwe warunkach, a 5 False, tak gęsta wersja będzie działać tak samo dobrze:

In [612]: nmask=sparse.csr_matrix(~(mask.A)) 
In [615]: a.multiply(nmask) 
Out[615]: 
<3x3 sparse matrix of type '<class 'numpy.int32'>' 
    with 2 stored elements in Compressed Sparse Row format> 

CSR scipy matrix does not update after updating its values bada ustawienie przekątnej rozrzedzony matrycy 0. Możliwe jest ustawienie wartości data atrybut 0, a następnie eliminate_zeros raz na końcu.

Druga metoda gęsta jest

In [618]: a1=a.A 
In [619]: a1[mask.A]=0 

Działa to również w sparse - rodzaj

In [622]: a2=a.copy() 
In [624]: a2[mask] 
Out[624]: matrix([[0, 3, 5, 0]], dtype=int32) 
In [625]: a2[mask]=0 
/usr/local/lib/python3.5/dist-packages/scipy/sparse/compressed.py:730: SparseEfficiencyWarning: Changing the sparsity structure of a csr_matrix is expensive. lil_matrix is more efficient. 
    SparseEfficiencyWarning) 
In [626]: a2 
Out[626]: 
<3x3 sparse matrix of type '<class 'numpy.int32'>' 
    with 6 stored elements in Compressed Sparse Row format> 

Jak wspomniano w poprzednim pytaniu, musimy wyeliminować zer:

In [628]: a2.eliminate_zeros() 
In [629]: a2 
Out[629]: 
<3x3 sparse matrix of type '<class 'numpy.int32'>' 
    with 2 stored elements in Compressed Sparse Row format> 

Podpowiedzi od ostrzeżenia o złośliwości spróbujmy wypróbować format lil

In [638]: al=a.tolil() 
In [639]: al[mask] 
Out[639]: 
<1x4 sparse matrix of type '<class 'numpy.int32'>' 
    with 2 stored elements in LInked List format> 
In [640]: al[mask]=0 
In [641]: al 
Out[641]: 
<3x3 sparse matrix of type '<class 'numpy.int32'>' 
    with 2 stored elements in LInked List format> 

To ciekawe, że al[mask] jest nadal rzadkie, gdzie jako a[mask] jest gęsta. Dwa formaty używają różnych metod indeksowania.

Przy pewnym niskim poziomie rzadkości może być warta powtórzenia po elementach True (niezerowych) mask, ustawiając odpowiednie warunki a na zero bezpośrednio.

Nie zamierzam zgadywać względnych prędkości tych metod. To musi być przetestowane na realistycznych danych.

+0

Tak jak mówisz, nie mogę zastosować ~ do matrycy, ponieważ rzeczywisty kształt matrycy jest za duży. Nalegam [maska] = 0, ale zajęło to ponad minutę. Właśnie wpadłem na pomysł użycia polecenia .data /elimin_zeros do sesji odpowiedzi (dodaj do ostatniego pytania). Mam zamiar wypróbować to na rzeczywistych danych w poniedziałek. Dzięki! – hiroto1228

+0

Próbowałem nowej metody na rzeczywistych danych, ale zajęło to dwa razy dłużej niż metoda mnożenia. – hiroto1228

+0

Nie jestem zbyt zaskoczony. – hpaulj