JustANoob
JustANoob

Reputation: 620

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?

Upvotes: 14

Views: 30030

Answers (8)

Anastasiya-Romanova 秀
Anastasiya-Romanova 秀

Reputation: 3378

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])

Upvotes: 0

Muhammad Yasirroni
Muhammad Yasirroni

Reputation: 2167

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)

Upvotes: 1

Sarvesh Pathak
Sarvesh Pathak

Reputation: 1

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

Upvotes: 0

debrises
debrises

Reputation: 105

iverted = ~arr + 2 should do the work

Upvotes: 2

Paul Panzer
Paul Panzer

Reputation: 53089

a^(a&1==a)

for example

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

Upvotes: 9

JChat
JChat

Reputation: 814

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])

Upvotes: 3

yatu
yatu

Reputation: 88305

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]])

Upvotes: 26

RemcoGerlich
RemcoGerlich

Reputation: 31270

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.

Upvotes: 9

Related Questions