J'ai un tableau 2D NumPy et voudrais remplacer toutes les valeurs supérieures ou égales à un seuil T avec 255.0. À ma connaissance, le moyen le plus fondamental serait:
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
Quel est le moyen le plus concis et pythonique de le faire?
Y at-il un moyen plus rapide (peut-être moins concis et/ou moins Pythonic) de le faire?
Cela fera partie d'un sous-programme de réglage de fenêtre/niveau pour les examens IRM de la tête humaine. Le tableau numpy 2D correspond aux données de pixels de l’image.
Je pense que le moyen le plus rapide et le plus concis de procéder consiste à utiliser l'indexation Fancy intégrée de NumPy. Si vous avez une ndarray
nommée arr
, vous pouvez remplacer tous les éléments >255
par une valeur x
comme suit:
arr[arr > 255] = x
Je l'ai exécuté sur ma machine avec une matrice aléatoire de 500 x 500, en remplaçant toutes les valeurs> 0,5 par 5, et cela a pris en moyenne 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
Puisque vous voulez réellement un tableau différent qui est arr
où arr < 255
et 255
sinon, vous pouvez le faire simplement:
result = np.minimum(arr, 255)
Plus généralement, pour une limite inférieure et/ou supérieure:
result = np.clip(arr, 0, 255)
Si vous voulez juste accéder aux valeurs supérieures à 255, ou quelque chose de plus compliqué, la réponse de @ mtitan8 est plus générale, mais np.clip
et np.minimum
(ou np.maximum
) sont plus agréables et plus rapides pour votre ordinateur. Cas:
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 vous voulez le faire sur place (c'est-à-dire, modifier arr
au lieu de créer result
), vous pouvez utiliser le paramètre out
de np.minimum
:
np.minimum(arr, 255, out=arr)
ou
np.clip(arr, 0, 255, arr)
(Le nom out=
est facultatif, car les arguments sont dans le même ordre que la définition de la fonction.)
Pour la modification sur place, l'indexation booléenne accélère beaucoup (sans avoir à créer puis à modifier la copie séparément), mais n'est pas aussi rapide que 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
À titre de comparaison, si vous vouliez restreindre vos valeurs avec un minimum aussi bien qu'un maximum, sans clip
, vous devrez le faire deux fois, avec quelque chose comme:
np.minimum(a, 255, a)
np.maximum(a, 0, a)
ou,
a[a>255] = 255
a[a<0] = 0
Je pense que vous pouvez y arriver le plus rapidement en utilisant la fonction where
:
Par exemple, recherchez des éléments supérieurs à 0,2 dans un tableau numpy et remplacez ceux-ci par 0:
import numpy as np
nums = np.random.Rand(4,3)
print np.where(nums > 0.2, 0, nums)
Vous pouvez envisager d'utiliser numpy.putmask:
np.putmask(arr, arr>=T, 255.0)
Voici une comparaison des performances avec l'indexation intégrée 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
Une autre méthode consiste à utiliser np.place
qui effectue le remplacement sur place et fonctionne avec des tableaux multidimensionnels:
import numpy as np
arr = np.arange(6).reshape(2, 3)
np.place(arr, arr == 0, -10)
Vous pouvez également utiliser &
, |
(et/ou) pour plus de flexibilité:
valeurs comprises entre 5 et 10: A[(A>5)&(A<10)]
valeurs supérieures à 10 ou inférieures à 5: A[(A<5)|(A>10)]