14

Let's say I have a numpy array where I would like to swap all the 1's to 0 and all the 0's to 1 (the array will have other values, and there is nothing special about the 0's and 1's). Of course, I can loop through the array and change the values one by one.

Is there an efficient method you can recommend using? Does the np.where() method have an option for this operation?

8 Answers 8

26

Here's one way using np.where, and taking the bitwise XOR of a given value when it is either 0 or 1:

np.where((a==0)|(a==1), a^1, a) 

For example:

a = np.array([[0,1,2,1], [1,2,0,3]]) print(a) array([[0, 1, 2, 1], [1, 2, 0, 3]]) np.where((a==0)|(a==1), a^1, a) array([[1, 0, 2, 0], [0, 2, 1, 3]]) 
Sign up to request clarification or add additional context in comments.

6 Comments

a^1 that was super clever :-)
Ref stackoverflow.com/questions/2451386/… for those (like me!) who don't know what ^ does...
You can equally use 1-a, by the way.
If the array is unsigned integers, your 2 tests could probably be made simpler/faster with the single test a<2, also by the way ;-)
Yes, in such case it would be a nice simplification :) @MarkSetchell
|
9

This is a less clever option with np.where, just using it for indexing:

where_0 = np.where(arr == 0) where_1 = np.where(arr == 1) arr[where_0] = 1 arr[where_1] = 0 

If you know more about the other values (e.g. they're all small numbers) there may be more options, but this is simplest.

1 Comment

Perhaps other than using twice np.where you could use np.select?
9
a^(a&1==a) 

for example

a = np.arange(-3, 4) a^(a&1==a) # array([-3, -2, -1, 1, 0, 2, 3]) 

5 Comments

Ha! Well this is neat! Had to run myself to understand what (a&1==a) does here :)
@yatu yeah, there can't be too many people who know the operator precedence here. I certainly had to go by trial and error ;-]
I like this. I always prefer calculating a result to if / else.
Awesome! Probably not the most semantic but definitely the most optimized.
The best way to go. Please upvote this answer. Benchmark see my answer
3

A very simple way which does not require the use of any special method such as np.where() is to get the indices for the conditions of the variables in your numpy array, and accordingly assign the required value (in your case 0 for 1s and 1 for 0s) to the respective positional items in the array. This works for values other than 0s and 1s too. Also, you don't require any temporary variable to swap the values.

import numpy as np arr = np.array([1, 0, 2, 3, 6, 1, 0]) indices_one = arr == 1 indices_zero = arr == 0 arr[indices_one] = 0 # replacing 1s with 0s arr[indices_zero] = 1 # replacing 0s with 1s Output: array([0, 1, 2, 3, 6, 0, 1]) 

1 Comment

Note to readers: much better (faster and more general) solutions below
2

iverted = ~arr + 2 should do the work

1 Comment

Be aware that this answer can't handle the array will have other values. For example, 4 will be -3.
1

The trickiest part is the array will have other values. In case only 0 and 1 (no other value), arr = ~arr + 2 is the fastest way. If the array will have other values needs to be considered, use arr^(arr&1==arr). Here is the benchmark.

%%timeit np.random.seed(0) arr = np.random.randint(0,2,100) arr = ~arr + 2 
38.8 µs ± 12 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
%%timeit np.random.seed(0) arr = np.random.randint(0,2,100) where_1 = arr == 1 where_0 = arr == 0 arr[where_1] = 0 # replacing 1s with 0s arr[where_0] = 1 # replacing 0s with 1s 
45.2 µs ± 7.02 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
%%timeit np.random.seed(0) arr = np.random.randint(0,2,100) arr = arr^(arr&1==arr) 
40.3 µs ± 7.8 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
%%timeit np.random.seed(0) arr = np.random.randint(0,2,100) where_1 = np.where(arr == 1) where_0 = np.where(arr == 0) arr[where_0] = 1 arr[where_1] = 0 
49.1 µs ± 13.4 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 
%%timeit np.random.seed(0) arr = np.random.randint(0,2,100) arr = np.where((arr==0)|(arr==1), arr^1, arr) 
52.3 µs ± 11.5 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each) 

Comments

0

inverted = ~arr + 2, did the trick for me as my array was of 8 bits

The '~' operator flips all the bits of the integer in the array from 0 to 1 and vice versa. For example, if you have the integer 0 represented by eight bits (one byte) 0000 0000, the tilde operation ~0000 0000 results in the value 1111 1111 which is the integer value -1, reference

so if a = 0, ~a gives -1 and (~a+2) gives 1 and if a = 1, ~a gives -2 and (~a+2) gives 0

Comments

0

I'm really surprised that no one thought of this before. The easiest and most efficient way to flip the values in a numpy array (arr) consisting of 0s and 1s is simply by subtracting the numpy array from 1. In other word, performing the operation 1 - arr. Here's a quick example:

arr = np.array([1, 0, 1, 1, 0]) 1 - arr 
array([0, 1, 0, 0, 1]) 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.