1

Say, I have a 2D numpy array consists of 20 elements, for example:

arr = np.array([[1, 2, 15, 7],[9, 11, 17, 19],[5, 7, 5, 8],[19, 4, 1, 45],[10, 7, 14, 8]])

and an additional array:

to_zero = np.array([0, 2, 1, 3, 2])

now, for each row i I would like to make the last to_zero[i] elements equal to zero, so eventually we will get the following result:

res = np.array([[1, 2, 15, 7],[9, 11, 0, 0],[5, 7, 5, 0],[19, 0, 0, 0],[10, 7, 0, 0]])

I would like to do this operation on a very big array. Is there any way to do this operation vectorized, with no loops, and no auxiliary arrays?

1

1 Answer 1

5

Use broadcasted-comparison to get a mask of those trailing ones and then mask the input -

In [63]: r = np.arange(arr.shape[1])[::-1]

In [66]: mask = to_zero[:,None]>r

In [69]: mask # mask of trailing places to be reset in input
Out[69]: 
array([[False, False, False, False],
       [False, False,  True,  True],
       [False, False, False,  True],
       [False,  True,  True,  True],
       [False, False,  True,  True]])

In [67]: arr[mask] = 0

In [68]: arr
Out[68]: 
array([[ 1,  2, 15,  7],
       [ 9, 11,  0,  0],
       [ 5,  7,  5,  0],
       [19,  0,  0,  0],
       [10,  7,  0,  0]])

Alternative to getting r would be with np.arange(arr.shape[1]-1,-1,-1).

Alternative to get the final output with element-wise multiplication : arr*~mask.

Or construct the flipped-mask with the flipped-comparison and then multiply -

In [75]: arr*(to_zero[:,None]<=np.arange(arr.shape[1]-1,-1,-1))
Out[75]: 
array([[ 1,  2, 15,  7],
       [ 9, 11,  0,  0],
       [ 5,  7,  5,  0],
       [19,  0,  0,  0],
       [10,  7,  0,  0]])

For large arrays, leverage multi-cores with numexpr -

In [78]: import numexpr as ne

In [79]: ne.evaluate('arr*mask',{'mask':to_zero[:,None]<=np.arange(arr.shape[1]-1,-1,-1)})
Out[79]: 
array([[ 1,  2, 15,  7],
       [ 9, 11,  0,  0],
       [ 5,  7,  5,  0],
       [19,  0,  0,  0],
       [10,  7,  0,  0]])
Sign up to request clarification or add additional context in comments.

3 Comments

Is there any way to do this operation vectorized, with no auxiliary arrays as noted in the question?
@aviyaChe Basically you are asking for a builtin and sadly there isn't any in NumPy. Also, we are constructing a mask/boolean array that occupies 1/8th of an int array on unix systems.
Even though the selection for a given row is a slice, the selection for the whole array requires some form of advanced indexing, identifying each element. That's what the mask does.

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.