Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace all elements of Python NumPy Array that are greater than some value

I have a 2D NumPy array and would like to replace all values in it greater than or equal to a threshold T with 255.0. To my knowledge, the most fundamental way would be:

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. What is the most concise and pythonic way to do this?

  2. Is there a faster (possibly less concise and/or less pythonic) way to do this?

This will be part of a window/level adjustment subroutine for MRI scans of the human head. The 2D numpy array is the image pixel data.

like image 704
NLi10Me Avatar asked Oct 29 '13 18:10

NLi10Me


People also ask

How do I remove multiple elements from a numpy array?

One way to remove multiple elements from a NumPy array is by calling the numpy. delete() function repeatedly for a bunch of indices.

How do you change the value of an array in Python?

We can replace values inside the list using slicing. First, we find the index of variable that we want to replace and store it in variable 'i'. Then, we replace that item with a new value using list slicing.


2 Answers

I think both the fastest and most concise way to do this is to use NumPy's built-in Fancy indexing. If you have an ndarray named arr, you can replace all elements >255 with a value x as follows:

arr[arr > 255] = x 

I ran this on my machine with a 500 x 500 random matrix, replacing all values >0.5 with 5, and it took an average of 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 
like image 119
mdml Avatar answered Sep 28 '22 17:09

mdml


Since you actually want a different array which is arr where arr < 255, and 255 otherwise, this can be done simply:

result = np.minimum(arr, 255) 

More generally, for a lower and/or upper bound:

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

If you just want to access the values over 255, or something more complicated, @mtitan8's answer is more general, but np.clip and np.minimum (or np.maximum) are nicer and much faster for your case:

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 

If you want to do it in-place (i.e., modify arr instead of creating result) you can use the out parameter of np.minimum:

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

or

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

(the out= name is optional since the arguments in the same order as the function's definition.)

For in-place modification, the boolean indexing speeds up a lot (without having to make and then modify the copy separately), but is still not as fast as 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 

For comparison, if you wanted to restrict your values with a minimum as well as a maximum, without clip you would have to do this twice, with something like

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

or,

a[a>255] = 255 a[a<0] = 0 
like image 40
askewchan Avatar answered Sep 28 '22 19:09

askewchan