'Change 1's to 0 and 0's to 1 in numpy array without looping
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?
Solution 1:[1]
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])
Solution 2:[2]
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]])
Solution 3:[3]
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.
Solution 4:[4]
a^(a&1==a)
for example
a = np.arange(-3, 4)
a^(a&1==a)
# array([-3, -2, -1, 1, 0, 2, 3])
Solution 5:[5]
iverted = ~arr + 2
should do the work
Solution 6:[6]
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)
Solution 7:[7]
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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | JChat |
Solution 2 | |
Solution 3 | RemcoGerlich |
Solution 4 | Paul Panzer |
Solution 5 | ?????????? ??????? |
Solution 6 | Muhammad Yasirroni |
Solution 7 | Sarvesh Pathak |