Aizstāt visus Python NumPy masīva elementus, kas ir lielāki par kādu vērtību

Man ir 2D NumPy masīvs, un es vēlētos aizstāt visas vērtības, kas tajā ir lielākas vai vienādas ar robežvērtību T, ar 255,0. Cik man zināms, visvienkāršākais veids būtu:

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. Kāds ir kodolīgākais un pitoniskākais veids, kā to izdarīt?

  2. Vai ir kāds ātrāks (iespējams, mazāk kodolīgs un/vai mazāk pitonisks) veids, kā to izdarīt?

Tas būs daļa no loga/līmeņa pielāgošanas apakšprogrammas cilvēka galvas magnētiskās rezonanses skenēšanai. 2D numpy masīvs ir attēla pikseļu dati.

Risinājums

Manuprāt, ātrākais un kodolīgākais veids, kā to izdarīt, ir izmantot NumPy iebūvēto Fancy indeksēšanu. Ja jums ir ndarray ar nosaukumu arr, jūs varat aizstāt visus elementus >255 ar vērtību x šādi:

arr[arr > 255] = x

Es to izmēģināju savā datorā ar 500 x 500 nejaušu matricu, aizstājot visas vērtības >0,5 ar 5, un tas aizņēma vidēji 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
Komentāri (9)

Tā kā jūs faktiski vēlaties citu masīvu, kas ir arr, ja arr < 255, un 255 citos gadījumos, to var izdarīt vienkārši:

result = np.minimum(arr, 255)

Vispārīgāk, lai noteiktu apakšējo un/vai augšējo robežu:

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

Ja vēlaties piekļūt tikai vērtībām virs 255 vai kam sarežģītākam, @mtitan8'atbilde ir vispārīgāka, bet np.clip un np.minimum (vai np.maximum) ir patīkamāka un daudz ātrāka jūsu gadījumā:

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

Ja vēlaties to izdarīt uz vietas (t.i., modificēt arr, nevis izveidot rezultātu), varat izmantot np.minimum parametru out:

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

vai

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

(out= vārds nav obligāts, jo argumenti ir tādā pašā secībā kā funkcijas definīcijā).)

Vietas modifikācijas gadījumā bolu indeksēšana ievērojami paātrina darbību (bez nepieciešamības atsevišķi izveidot un pēc tam modificēt kopiju), bet joprojām nav tik ātra kā 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

Salīdzinājumam, ja jūs vēlaties ierobežot vērtības ar minimumu un maksimumu, bez clip jums tas būtu jādara divreiz, izmantojot kaut ko līdzīgu.

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

vai,


a[a>255] = 255
a[a
Komentāri (4)

Varat apsvērt iespēju izmantot numpy.putmask:

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

Šeit ir snieguma salīdzinājums ar Numpy iebūvēto indeksēšanu:

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
Komentāri (1)