2

I want to write a function where if an array is equal to or less than 0 it will replace the values after (and including) that index with 0. The numbers have the 7th element less than 0 being -1, thus elements including the 7th element to 10th element values will be replaced by 0. How could I configure the the np.where function so it gives the expected result values?

Sample input:

numbers = np.array([87., 4., 4.1,  8.5, 10 , 20, 22.3, -1., 1., 60., -4.])

Expected output:

[87., 4., 4.1,  8.5, 10 , 20, 22.3, 0., 0., 0., 0.]
1
  • What have you tried so far? Commented Feb 8, 2021 at 3:02

3 Answers 3

3

You can use argmax to find out the first indice that's smaller than 0, and then modify all values after that indice to 0:

a = np.array([87. ,4., 4.1,  8.5, 10 , 20, 22.3, -1, 1, 60, -4])
if (a <= 0).any(): a[(a <= 0).argmax():] = 0

a
# [87.   4.   4.1  8.5 10.  20.  22.3  0.   0.   0.   0. ]

Or more efficiently, you can check the value under the candidate index only:

def zero_after_native(a):
    candidate = (a <= 0).argmax()
    if a[candidate] <= 0:
        a[candidate:] = 0

a = np.array([87. ,4., 4.1,  8.5, 10 , 20, 22.3, -1, 1, 60, -4])
zero_after_native(a)

a
# [87.   4.   4.1  8.5 10.  20.  22.3  0.   0.   0.   0. ]
Sign up to request clarification or add additional context in comments.

3 Comments

For some reason when I plug the values [13. 12.48 8.22432 8.9233872] it gives me [0. 0. 0. 0.] as the answer.
This only works if there's actually a zero, but you're very close
@tonyselcuk Yeah, you need a check to make sure there's at least one value satisfying the condition.
1

First off, don't use np.where. For what you have here, it's just a wrapper for np.nonzero, which you don't need because this can all be done using masks.

To correctly handle the case without any negatives, I'd recommend finding the last positive index rather than the first negative index, and setting everything to zero after that:

def zero_tail(a):
    a[a.size - (a >= 0)[::-1].argmax():] = 0

To check:

>>> a = np.arange(9, -5, -2)
>>> zero_tail(a)
>>> a

>>> a = np.arange(1, 10)
>>> zero_tail(a)
>>> a

If you absolutely wanted to use np.nonzero instead of np.argmax, you could do something similar (I'd actually recommend np.flatnonzero to avoid an extra layer of unpacking):

def zero_tail(a):
    a[a.size - np.flatnonzero((a >= 0)[::-1])[0]:] = 0

Comments

1

Another solution is:

Numbers[np.where(Numbers<=0)[0][0]:]=0

or equally:

Numbers[np.flatnonzero(Numbers<=0)[0]:]=0

or equally:

Numbers[np.nonzero(Numbers<=0)[0][0]:]=0

EDIT:

The above solutions work assuming you have at least one non-positive number in your array. If it is not guaranteed, you can use an if statement before them like:

if (Numbers<=0).any(): 
  Numbers[np.where(Numbers<=0)[0][0]:]=0

output:

array([87. ,  4. ,  4.1,  8.5, 10. , 20. , 22.3,  0. ,  0. ,  0. ,  0. ])

5 Comments

The np.where function gives me an error IndexError: index 0 is out of bounds for axis 0 with size 0
These all fail for cases without negative numbers
is there a way I could modify it so it does not fail?
@MadPhysicist Thank you for the catch. Added an edit pointing out your note.
@tonyselcuk added edition to it. However, the Madphysicist's solution above is better.

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.