2

I have a binary N-by-N (N~=200) NumPy array populated with zeroes and ones. I would like to apply a Boolean mask and 'swap' the values that correspond to True in the mask, so for example if I had:

arr = np.array([0,0,1,1],
               [0,0,1,1],
               [0,0,1,1],
               [0,0,1,1])
mask = np.array([True,False,True,False],
                [True,False,True,False],
                [True,False,True,False],
                [True,False,True,False],

I would like the resulting array to be:

arr_new = np.array([1,0,0,1],
                   [1,0,0,1],
                   [1,0,0,1],
                   [1,0,0,1])

I started this by initially creating a function swap_cell that swaps between the values, and then followed the approaches in this answer.

def swap_cell(x):
    if x == 1.0:
        return 0.0
    elif x == 0.0:
        return 1.0

arr_new = np.where(mask,swap_cell(arr),arr)

This code returns ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all(), which I understand is because of the 'if' statement in my swap_cell() function. I know there must be a much more pythonic way to accomplish this, but I thought this might work.

2 Answers 2

3

If you interpret the first (0,1) array as a boolean array, then you are doing the exclusive or operation of each entry in the first array with each entry of the second array.

Therefore, you can do this with the numpy function np.logical_xor() as follows:

arr = np.array([[0,0,1,1],
                [0,0,1,1],
                [0,0,1,1],
                [0,0,1,1]])
mask = np.array([[True,False,True,False],
                 [True,False,True,False],
                 [True,False,True,False],
                 [True,False,True,False]])

np.array(np.logical_xor(arr, mask), dtype=int)

which returns

array([[1, 0, 0, 1],
       [1, 0, 0, 1],
       [1, 0, 0, 1],
       [1, 0, 0, 1]])
Sign up to request clarification or add additional context in comments.

1 Comment

Alternatively: (mask!=arr).astype(int)
1

A simpler way would be to subtract 1 and take the absolute value:

def swap(x):
    return np.abs(x - 1)

Since this is able to operate on the entire array, you can apply the mask, pass the masked array to swap, and assign the returned value to the masked elements:

arr = np.array([[0,0,1,1],
               [0,0,1,1],
               [0,0,1,1],
               [0,0,1,1]])
mask = np.array([[True,False,True,False],
                [True,False,True,False],
                [True,False,True,False],
                [True,False,True,False]])

arr[mask] = swap(arr[mask])

which results in your expected array:

array([[1, 0, 0, 1],
       [1, 0, 0, 1],
       [1, 0, 0, 1],
       [1, 0, 0, 1]])

Another approach would be to convert the dtype to bool, then invert the array, and finally restore the original dtype:

def swap(x):
    return (~x.astype(bool)).astype(x.dtype)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.