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)