Jeg har et 2D NumPy-array og vil gerne erstatte alle værdier i det, der er større end eller lig med en tærskel T, med 255,0. Så vidt jeg ved, ville den mest grundlæggende måde være:
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
Hvad er den mest kortfattede og pythoniske måde at gøre dette på?
Er der en hurtigere (muligvis mindre kortfattet og/eller mindre pythonisk) måde at gøre dette på?
Dette vil være en del af en underrutine til vindues-/niveaujustering af MRI-scanninger af det menneskelige hoved. 2D numpy-arrayet er billedpixeldataene.
Jeg tror, at den hurtigste og mest overskuelige måde at gøre dette på er at bruge NumPy's indbyggede Fancy indexing. Hvis du har et ndarray
ved navn arr
, kan du erstatte alle elementer >255
med en værdi x
på følgende måde:
arr[arr > 255] = x
Jeg kørte dette på min maskine med en 500 x 500 tilfældig matrix, hvor jeg erstattede alle værdier >0,5 med 5, og det tog i gennemsnit 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
Da du faktisk ønsker et andet array, som er arr
hvor arr < 255
, og 255
ellers, kan dette gøres på en enkel måde:
result = np.minimum(arr, 255)
Mere generelt, for en nedre og/eller øvre grænse:
result = np.clip(arr, 0, 255)
Hvis du bare vil have adgang til værdierne over 255, eller noget mere kompliceret, er @mtitan8's svar mere generelt, men np.clip
og np.minimum
(eller np.maximum
) er pænere og meget hurtigere i dit tilfælde:
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
Hvis du vil gøre det in-place (dvs. ændre arr
i stedet for at oprette result
) kan du bruge parameteren out
i np.minimum
:
np.minimum(arr, 255, out=arr)
eller
np.clip(arr, 0, 255, arr)
(navnet out=
er valgfrit, da argumenterne er i samme rækkefølge som funktionens definition.)
Ved in-place modifikation er den boolske indeksering meget hurtigere (uden at skulle lave og derefter ændre kopien separat), men den er stadig ikke så hurtig som 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
Til sammenligning, hvis du ville begrænse dine værdier med et minimum såvel som et maksimum, ville du uden clip
være nødt til at gøre det to gange, med noget som
np.minimum(a, 255, a)
np.maximum(a, 0, a)
eller,
a[a>255] = 255
a[a<0] = 0
Du kan overveje at bruge numpy.putmask:
np.putmask(arr, arr>=T, 255.0)
Her er en sammenligning af ydeevne med Numpy's indbyggede indeksering:
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