Wymiana elementów Numpy, jeśli warunek jest spełniony


95

Mam dużą tablicę numpy, którą muszę manipulować, aby każdy element był zmieniany na 1 lub 0, jeśli warunek zostanie spełniony (będzie później używany jako maska ​​pikseli). W tablicy jest około 8 milionów elementów, a moja obecna metoda zajmuje zbyt dużo czasu dla potoku redukcji:

for (y,x), value in numpy.ndenumerate(mask_data): 

    if mask_data[y,x]<3: #Good Pixel
        mask_data[y,x]=1
    elif mask_data[y,x]>3: #Bad Pixel
        mask_data[y,x]=0

Czy jest jakaś funkcja numpy, która przyspieszyłaby to?


1
Co chcesz, żeby się stało mask_data[y,x]==3?
DSM

Słuszna uwaga, to nadal byłby zły piksel. Zmienię warunek naif mask_data[y,x]>=3:
ChrisFro

Odpowiedzi:


131
>>> import numpy as np
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[4, 2, 1, 1],
       [3, 0, 1, 2],
       [2, 0, 1, 1],
       [4, 0, 2, 3],
       [0, 0, 0, 2]])
>>> b = a < 3
>>> b
array([[False,  True,  True,  True],
       [False,  True,  True,  True],
       [ True,  True,  True,  True],
       [False,  True,  True, False],
       [ True,  True,  True,  True]], dtype=bool)
>>> 
>>> c = b.astype(int)
>>> c
array([[0, 1, 1, 1],
       [0, 1, 1, 1],
       [1, 1, 1, 1],
       [0, 1, 1, 0],
       [1, 1, 1, 1]])

Możesz to skrócić za pomocą:

>>> c = (a < 3).astype(int)

2
jak to zrobić z określonymi kolumnami bez wycinania niektórych kolumn i ponownego przypisywania? na przykład tylko elementy w kolumnach [2, 3] powinny zmieniać wartość po spełnieniu warunków, podczas gdy inne kolumny nie zmienią się bez względu na to, czy warunki są spełnione, czy nie.
kuixiong

Prawda, ale tylko w przypadku zer i jedynek. Zobacz bardziej ogólną odpowiedź poniżej (kosztem wydajności)
borgr

94
>>> a = np.random.randint(0, 5, size=(5, 4))
>>> a
array([[0, 3, 3, 2],
       [4, 1, 1, 2],
       [3, 4, 2, 4],
       [2, 4, 3, 0],
       [1, 2, 3, 4]])
>>> 
>>> a[a > 3] = -101
>>> a
array([[   0,    3,    3,    2],
       [-101,    1,    1,    2],
       [   3, -101,    2, -101],
       [   2, -101,    3,    0],
       [   1,    2,    3, -101]])
>>>

Zobacz np. Indeksowanie za pomocą tablic logicznych .


4
świetne rzeczy, dzięki! Jeśli chcesz odnieść się do wartości, którą zmieniasz, możesz użyć czegoś takiego jak a[a > 3] = -101+a[a > 3].
pexmar

2
@pexmar Chociaż jeśli to zrobisz a[a > 3] = -101+a[a > 3]zamiast a[a > 3] += -101ciebie, najprawdopodobniej napotkasz wyciek pamięci.
Samuel Prevost

2
jak odnosisz się do zmienianej wartości, o co pytał pexmar?
Juan

34

Najszybciej (i elastycznych) sposobem jest użycie np.where , które wybiera pomiędzy dwoma macierzy zgodnie z maską (tablica wartości rzeczywistych i fałszywych)

import numpy as np
a = np.random.randint(0, 5, size=(5, 4))
b = np.where(a<3,0,1)
print('a:',a)
print()
print('b:',b)

który wyprodukuje:

a: [[1 4 0 1]
 [1 3 2 4]
 [1 0 2 1]
 [3 1 0 0]
 [1 4 0 1]]

b: [[0 1 0 0]
 [0 1 0 1]
 [0 0 0 0]
 [1 0 0 0]
 [0 1 0 0]]

2
co będzie najlepszym sposobem, jeśli nie chcę niczego zastępować, jeśli warunek nie jest spełniony? tzn. zamień na wartość dostarczoną tylko wtedy, gdy warunek jest spełniony, jeśli nie, pozostaw oryginalny numer taki, jaki jest ....
Abhishek Sengupta

2
aby zamienić wszystkie wartości w a, które są mniejsze od 3 i pozostawić resztę tak, jak jest, użyja[a<3] = 0
Markus Dutschke

3

Możesz stworzyć swoją tablicę masek w jednym kroku

mask_data = input_mask_data < 3

Tworzy to tablicę logiczną, która może być następnie używana jako maska ​​pikseli. Zauważ, że nie zmieniliśmy tablicy wejściowej (tak jak w twoim kodzie), ale utworzyliśmy nową tablicę do przechowywania danych maski - zalecałbym zrobienie tego w ten sposób.

>>> input_mask_data = np.random.randint(0, 5, (3, 4))
>>> input_mask_data
array([[1, 3, 4, 0],
       [4, 1, 2, 2],
       [1, 2, 3, 0]])
>>> mask_data = input_mask_data < 3
>>> mask_data
array([[ True, False, False,  True],
       [False,  True,  True,  True],
       [ True,  True, False,  True]], dtype=bool)
>>> 

1
Tak. Jeśli OP naprawdę chce 0 i 1, mógłby użyć .astype(int)lub *1, ale tablica Truei Falsejest tak samo dobra, jak jest.
DSM

-4

Nie jestem pewien, czy zrozumiałem Twoje pytanie, ale jeśli napiszesz:

mask_data[:3, :3] = 1
mask_data[3:, 3:] = 0

Spowoduje to, że wszystkie wartości danych maski, których indeksy x i y są mniejsze niż 3, będą równe 1, a wszystkie pozostałe będą równe 0

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.