Reemplace todos los elementos de la matriz NumPy de Python que sean mayores que algún valor

Tengo una matriz NumPy 2D y me gustaría reemplazar todos los valores en ella mayores o iguales a un umbral T con 255.0. Que yo sepa, la forma más fundamental sería:

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. ¿Cuál es la forma más concisa y pythonica de hacer esto?

  2. ¿Hay una forma más rápida (posiblemente menos concisa y / o menos python) de hacer esto?

Esto formará parte de una subrutina de ajuste de ventana / nivel para imágenes de resonancia magnética de la cabeza humana. La matriz numpy 2D son los datos de píxeles de la imagen.

    Creo que la forma más rápida y concisa de hacer esto es utilizar la indexación integrada de Numpy. Si tiene un ndarray llamado arr , puede reemplazar todos los elementos >255 con un valor x siguiente manera:

     arr[arr > 255] = x 

    Corrí esto en mi máquina con una matriz aleatoria de 500 x 500, reemplazando todos los valores> 0.5 con 5, y tomé un promedio de 7.59ms.

     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 

    Ya que realmente desea una matriz diferente que es arr donde arr < 255 , y 255 contrario, esto se puede hacer simplemente:

     result = np.minimum(arr, 255) 

    Más generalmente, para un límite inferior y / o superior:

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

    Si solo desea acceder a los valores por encima de 255, o algo más complicado, la respuesta de @mtitan8 es más general, pero np.clip y np.minimum (o np.maximum ) son np.maximum y mucho más rápidos para su caso:

     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 

    Si desea hacerlo en el lugar (es decir, modificar arr lugar de crear un result ), puede usar el parámetro out de np.minimum :

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

    o

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

    ( out= name es opcional ya que los argumentos están en el mismo orden que la definición de la función).

    Para la modificación en el lugar, la indexación booleana acelera mucho (sin tener que hacer y luego modificar la copia por separado), pero aún no es tan rápido como 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 

    A modo de comparación, si desea restringir sus valores con un mínimo y un máximo, sin clip , tendría que hacer esto dos veces, con algo como

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

    o,

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

    Puedes considerar el uso de numpy.putmask :

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

    Aquí hay una comparación de rendimiento con la indexación integrada de 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 

    Creo que puedes lograr esto más rápido usando la función where :

    Por ejemplo, buscando elementos mayores de 0.2 en una matriz numpy y reemplazando aquellos con 0:

     import numpy as np nums = np.random.rand(4,3) print np.where(nums > 0.2, 0, nums) 

    Otra forma es usar np.place que realiza el reemplazo en el lugar y funciona con matrices multidimensionales:

     import numpy as np arr = np.arange(6).reshape(2, 3) np.place(arr, arr == 0, -10) 

    También puedes usar & , | (y / o) para mayor flexibilidad:

    valores entre 5 y 10: A[(A>5)&(A<10)]

    valores mayores que 10 o menores que 5: A[(A<5)|(A>10)]