Ich habe ein 2D-NumPy-Array und möchte alle Werte darin, die größer oder gleich einem Schwellenwert T sind, durch 255.0 ersetzen. Meines Wissens wäre der grundlegendste Weg:
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
Was ist der prägnanteste und pythonischste Weg, dies zu tun?
Gibt es eine schnellere (möglicherweise weniger präzise und/oder weniger pythonische) Möglichkeit, dies zu tun?
Dies ist Teil einer Subroutine zur Fenster-/Pegeleinstellung für MRT-Untersuchungen des menschlichen Kopfes. Das 2D-Numpy-Array enthält die Bildpixeldaten.
Ich denke, der schnellste und prägnanteste Weg, dies zu tun, ist die Verwendung der in NumPy integrierten Fancy-Indexierung. Wenn Sie ein ndarray
mit dem Namen arr
haben, können Sie alle Elemente >255
wie folgt durch einen Wert x
ersetzen:
arr[arr > 255] = x
Ich habe dies auf meinem Computer mit einer 500 x 500-Zufallsmatrix ausgeführt, wobei alle Werte> 0,5 durch 5 ersetzt wurden, und es dauerte durchschnittlich 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 Sie tatsächlich ein anderes Array wünschen, das arr
where arr < 255
und 255
ist, kann dies einfach durchgeführt werden:
result = np.minimum(arr, 255)
Allgemeiner für eine untere und/oder obere Schranke:
result = np.clip(arr, 0, 255)
Wenn Sie nur auf Werte über 255 oder etwas Komplizierteres zugreifen möchten, ist die Antwort von @ mtitan8 allgemeiner, aber np.clip
und np.minimum
(oder np.maximum
) sind schöner und viel schneller für Sie Fall:
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
Wenn Sie dies direkt ausführen möchten (d. H. arr
ändern, anstatt result
zu erstellen), können Sie den out
-Parameter von np.minimum
verwenden:
np.minimum(arr, 255, out=arr)
oder
np.clip(arr, 0, 255, arr)
(Der Name out=
ist optional, da die Argumente in derselben Reihenfolge wie die Definition der Funktion angegeben sind.)
Bei direkten Änderungen beschleunigt sich die boolesche Indizierung erheblich (ohne dass die Kopie separat erstellt und anschließend geändert werden muss), ist jedoch immer noch nicht so schnell wie 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
Zum Vergleich: Wenn Sie Ihre Werte sowohl mit einem Minimum als auch mit einem Maximum einschränken möchten, ohne clip
, müssen Sie dies zweimal mit so etwas tun
np.minimum(a, 255, a)
np.maximum(a, 0, a)
oder,
a[a>255] = 255
a[a<0] = 0
Ich denke, Sie können dies am schnellsten erreichen, indem Sie die Funktion where
verwenden:
Suchen Sie beispielsweise nach Elementen, die größer als 0,2 sind, und ersetzen Sie diese durch 0:
import numpy as np
nums = np.random.Rand(4,3)
print np.where(nums > 0.2, 0, nums)
Sie können erwägen, numpy.putmask zu verwenden:
np.putmask(arr, arr>=T, 255.0)
Hier ist ein Leistungsvergleich mit der integrierten Indexierung des 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
Eine andere Möglichkeit ist die Verwendung von np.place
, das das Ersetzen vor Ort durchführt und mit multidimentionalen Arrays funktioniert:
import numpy as np
arr = np.arange(6).reshape(2, 3)
np.place(arr, arr == 0, -10)
Sie können auch &
, |
(und/oder) für mehr Flexibilität verwenden:
werte zwischen 5 und 10: A[(A>5)&(A<10)]
werte größer als 10 oder kleiner als 5: A[(A<5)|(A>10)]