Zastąp wszystkie elementy tablicy Python NumPy, które są większe niż pewna wartość


190

Mam tablicę 2D NumPy i chciałbym zastąpić w niej wszystkie wartości większe lub równe progowi T o wartości 255.0. Według mojej wiedzy najbardziej fundamentalnym sposobem byłoby:

shape = arr.shape
result = np.zeros(shape)
for x in range(0, shape[0]):
    for y in range(0, shape[1]):
        if arr[x, y] >= T:
            result[x, y] = 255
  1. Jaki jest najbardziej zwięzły i pytonowy sposób na zrobienie tego?

  2. Czy istnieje szybszy (być może mniej zwięzły i / lub mniej pytoniczny) sposób na zrobienie tego?

Będzie to część podprogramu regulacji okna / poziomu dla skanów MRI ludzkiej głowy. Tablica numpy 2D to dane pikseli obrazu.


Aby uzyskać więcej informacji, zapoznaj się z tym wprowadzeniem do indeksowania .
— askewchan

Odpowiedzi:


332

Myślę, że najszybszym i najbardziej zwięzłym sposobem na zrobienie tego jest użycie wbudowanego indeksowania NumPy Fancy. Jeśli masz ndarraynazwę arr, możesz zastąpić wszystkie elementy >255wartością xw następujący sposób:

arr[arr > 255] = x

Uruchomiłem to na mojej maszynie z losową matrycą 500 x 500, zastępując wszystkie wartości> 0,5 wartością 5, i zajęło to średnio 7,59 ms.

In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)
In [3]: timeit A[A > 0.5] = 5
100 loops, best of 3: 7.59 ms per loop

3
Zauważ, że modyfikuje to istniejącą tablicę arr, zamiast tworzyć resulttablicę jak w OP.
— askewchan

1
Czy istnieje sposób, aby to zrobić, nie modyfikując, Aale tworząc nową tablicę?
— azotan sodu

Co byśmy zrobili, gdybyśmy chcieli zmienić wartości przy indeksach, które są wielokrotnościami danego n, np. [2], a [4], a [6], a [8] ..... dla n = 2?
— lavee_singh

100 pętli, najlepiej 3: 2,22 ms na pętlę
— dreab

5
UWAGA: to nie działa, jeśli dane znajdują się na liście python, MUSI znajdować się w tablicy numpy ( np.array([1,2,3])
— mjp

46

Ponieważ tak naprawdę potrzebujesz innej tablicy, która jest arrtam arr < 255, gdzie 255indziej, można to zrobić po prostu:

result = np.minimum(arr, 255)

Mówiąc bardziej ogólnie, dla dolnej i / lub górnej granicy:

result = np.clip(arr, 0, 255)

Jeśli chcesz uzyskać dostęp do wartości powyżej 255 lub coś bardziej skomplikowanego, odpowiedź @ mtitan8 jest bardziej ogólna, ale np.clipi np.minimum(lub np.maximum) jest ładniejsza i znacznie szybsza w twoim przypadku:

In [292]: timeit np.minimum(a, 255)
100000 loops, best of 3: 19.6 µs per loop

In [293]: %%timeit
   .....: c = np.copy(a)
   .....: c[a>255] = 255
   .....: 
10000 loops, best of 3: 86.6 µs per loop

Jeśli chcesz to zrobić w miejscu (tj. Zmodyfikować arrzamiast tworzyć result), możesz użyć outparametru np.minimum:

np.minimum(arr, 255, out=arr)

lub

np.clip(arr, 0, 255, arr)

( out=nazwa jest opcjonalna, ponieważ argumenty w tej samej kolejności, co definicja funkcji).

W przypadku modyfikacji na miejscu indeksowanie logiczne znacznie przyspiesza (bez konieczności wykonywania, a następnie modyfikowania kopii osobno), ale nadal nie jest tak szybkie, jak minimum:

In [328]: %%timeit
   .....: a = np.random.randint(0, 300, (100,100))
   .....: np.minimum(a, 255, a)
   .....: 
100000 loops, best of 3: 303 µs per loop

In [329]: %%timeit
   .....: a = np.random.randint(0, 300, (100,100))
   .....: a[a>255] = 255
   .....: 
100000 loops, best of 3: 356 µs per loop

Dla porównania, jeśli chcesz ograniczyć swoje wartości z minimum, jak i maksimum, bez clipkonieczności robienia tego dwa razy, z czymś takim jak

np.minimum(a, 255, a)
np.maximum(a, 0, a)

lub,

a[a>255] = 255
a[a<0] = 0

1
Bardzo dziękuję za cały komentarz, jednak np. Klip i np. Minimum nie wydają się być tym, czego potrzebuję w tym przypadku, w PO widać, że próg T i wartość zastępcza (255) niekoniecznie są takie same numer. Nadal jednak oddałem głos za dokładnością. Dzięki jeszcze raz.
— NLi10Me

Co byśmy zrobili, gdybyśmy chcieli zmienić wartości przy indeksach, które są wielokrotnościami danego n, np. [2], a [4], a [6], a [8] ..... dla n = 2?
— lavee_singh

@lavee_singh, aby to zrobić, możesz użyć trzeciej części plastra, która jest zwykle zaniedbywana: a[start:stop:step]daje elementy tablicy od startdo stop, ale zamiast każdego elementu, zajmuje tylko każdy step(jeśli zostanie pominięty, 1domyślnie jest ). Aby więc wyzerować wszystkie a[::2] = 0
— znaki

Dzięki, potrzebowałem czegoś takiego, chociaż znałem to dla prostych list, ale nie wiedziałem, czy i jak to działa dla numpy.array.
— lavee_singh

14

Myślę, że możesz to zrobić najszybciej, używając wherefunkcji:

Na przykład szukanie elementów większych niż 0,2 w tablicy numpy i zamiana tych na 0:

import numpy as np

nums = np.random.rand(4,3)

print np.where(nums > 0.2, 0, nums)

10

Możesz rozważyć użycie numpy.putmask :

np.putmask(arr, arr>=T, 255.0)

Oto porównanie wydajności z wbudowanym indeksowaniem Numpy:

In [1]: import numpy as np
In [2]: A = np.random.rand(500, 500)

In [3]: timeit np.putmask(A, A>0.5, 5)
1000 loops, best of 3: 1.34 ms per loop

In [4]: timeit A[A > 0.5] = 5
1000 loops, best of 3: 1.82 ms per loop

8

Innym sposobem jest użycie, np.placektóre zastępuje w miejscu i działa z tablicami wielowymiarowymi:

import numpy as np

# create 2x3 array with numbers 0..5
arr = np.arange(6).reshape(2, 3)

# replace 0 with -10
np.place(arr, arr == 0, -10)

To jest rozwiązanie, którego użyłem, ponieważ było to pierwsze, z którym się spotkałem. Zastanawiam się, czy istnieje duża różnica między tym a wybraną odpowiedzią powyżej. Co myślisz?
— jonathanking

W moich bardzo ograniczonych testach mój powyższy kod z np.place działa 2 razy wolniej niż metoda bezpośredniego indeksowania przyjętej odpowiedzi. To zaskakujące, ponieważ myślałem, że np. Miejsce byłoby bardziej zoptymalizowane, ale myślę, że prawdopodobnie włożyli więcej pracy w bezpośrednie indeksowanie.
— Shital Shah

W moim przypadku np.placebył również wolniejszy w porównaniu do metody wbudowanej, chociaż w tym komentarzu twierdzi się coś przeciwnego.
— riyansh.legend

3

Możesz także użyć &, |(i / lub) dla większej elastyczności:

wartości od 5 do 10: A[(A>5)&(A<10)]

wartości większe niż 10 lub mniejsze niż 5: A[(A<5)|(A>10)]

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.