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

Resuelto NLi10Me asked hace 11 años • 8 respuestas

Tengo una matriz NumPy 2D. ¿Cómo reemplazo todos los valores mayores que un umbral T = 255con un valor x = 255? Un método lento basado en bucle for sería:

# arr = arr.copy()  # Optionally, do not modify original arr.

for i in range(arr.shape[0]):
    for j in range(arr.shape[1]):
        if arr[i, j] > 255:
            arr[i, j] = x
NLi10Me avatar Oct 30 '13 01:10 NLi10Me
Aceptado

Creo que la forma más rápida y concisa de hacer esto es utilizar la indexación Fancy incorporada de NumPy. Si tiene un ndarraynombre arr, puede reemplazar todos los elementos >255con un valor xde la siguiente manera:

arr[arr > 255] = x

Ejecuté esto en mi máquina con una matriz aleatoria de 500 x 500, reemplazando todos los valores >0,5 por 5, y tardó un promedio de 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
mdml avatar Oct 29 '2013 18:10 mdml

Si desea una nueva matriz resultque contenga una copia de arrsiempre arr < 255y 255en caso contrario:

result = np.minimum(arr, 255)

De manera más general, para un límite inferior y/o superior:

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

Si solo desea acceder a los valores superiores a 255, o algo más complicado, la respuesta de @mtitan8 es más general, pero np.clipy np.minimum(o np.maximum) son mejores 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 in situ (es decir, modificar arren lugar de crear result), puede utilizar el outparámetro de np.minimum:

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

o

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

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

Para la modificación in situ, la indexación booleana se acelera mucho (sin tener que hacer y luego modificar la copia por separado), pero aún no es tan rápida 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 quisiera restringir sus valores tanto con un mínimo como con un máximo, cliptendría que hacerlo dos veces, con algo como

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

o,

a[a>255] = 255
a[a<0] = 0
askewchan avatar Oct 29 '2013 19:10 askewchan

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

Por ejemplo, buscar elementos mayores que 0,2 en una matriz numerosa y reemplazarlos con 0:

import numpy as np

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

print np.where(nums > 0.2, 0, nums)
Amir F avatar Jan 09 '2017 21:01 Amir F