Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast value swapping in numpy array

So, this is something, that should be pretty easy, but it seems to take an enormous amount of time for me: I have a numpy array with only two values (example 0 and 255) and I want to invert the matrix in that way, that all values swap (0 becomes 255 and vice versa). The matrices are about 2000³ entries big, so this is serious work! I first tried the numpy.invert method, which is not exactly what I expected. So I tried to do that myself by "storing" the values and then override them:

for i in range(array.length):
            array[i][array[i]==255]=1
            array[i][array[i]==0]=255
            array[i][array[i]==1]=0

which is behaving as expected, but taking a long time (I guess due to the for loop?). Would that be faster if I implement that as a multithreaded calculation, where every thread "inverts" a smaller sub-array? Or is there another way of doing that more conveniently?

like image 909
Dschoni Avatar asked Jan 18 '26 07:01

Dschoni


2 Answers

In addition to @JanneKarila's and @EOL's excellent suggestions, it's worthwhile to show a more efficient approach to using a mask to do the swap.

Using a boolean mask is more generally useful if you have a more complex comparison than simply swapping two values, but your example uses it in a sub-optimal way.

Currently, you're making multiple temporary copies of the boolean "mask" array (e.g. array[i] == blah) in your example above and performing multiple assignments. You can avoid this by just making the "mask" boolean array once and the inverting it.

If you have enough ram for a temporary copy (of bool dtype), try something like this:

mask = (data == 255)
data[mask] = 0
data[~mask] = 255

Alternately (and equivalently) you could use numpy.where:

data = numpy.where(data == 255, 0, 255)

If you were using a loop to avoid making a full temporary copy, and need to conserve ram, adjust your loop to be something more like this:

for i in range(len(array)):
     mask = (array[i] == 255)
     array[mask] = 0
     array[~mask] = 255

All that having been said, either subtraction or XOR is the way to go in this case, especially if you preform the operation in-place!

like image 179
Joe Kington Avatar answered Jan 20 '26 02:01

Joe Kington


To swap 0 and 255, you can use XOR if the data type is one of the integer types.

array ^= 255
like image 39
Janne Karila Avatar answered Jan 20 '26 01:01

Janne Karila



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!