Replace negative values in an numpy array

PythonNumpy

Python Problem Overview


Is there a simple way of replacing all negative values in an array with 0?

I'm having a complete block on how to do it using a NumPy array.

E.g.

a = array([1, 2, 3, -4, 5])

I need to return

[1, 2, 3, 0, 5]

a < 0 gives:

[False, False, False, True, False]

This is where I'm stuck - how to use this array to modify the original array.

Python Solutions


Solution 1 - Python

You are halfway there. Try:

In [4]: a[a < 0] = 0

In [5]: a
Out[5]: array([1, 2, 3, 0, 5])

Solution 2 - Python

Try numpy.clip:

>>> import numpy
>>> a = numpy.arange(-10, 10)
>>> a
array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,
         3,   4,   5,   6,   7,   8,   9])
>>> a.clip(0, 10)
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

You can clip only the bottom half with clip(0).

>>> a = numpy.array([1, 2, 3, -4, 5])
>>> a.clip(0)
array([1, 2, 3, 0, 5])

You can clip only the top half with clip(max=n). (This is much better than my previous suggestion, which involved passing NaN to the first parameter and using out to coerce the type.):

>>> a.clip(max=2)
array([ 1,  2,  2, -4,  2])

Another interesting approach is to use where:

>>> numpy.where(a <= 2, a, 2)
array([ 1,  2,  2, -4,  2])

Finally, consider aix's answer. I prefer clip for simple operations because it's self-documenting, but his answer is preferable for more complex operations.

Solution 3 - Python

Another minimalist Python solution without using numpy:

[0 if i < 0 else i for i in a]

No need to define any extra functions.

a = [1, 2, 3, -4, -5.23, 6]
[0 if i < 0 else i for i in a]

yields:

[1, 2, 3, 0, 0, 6]

Solution 4 - Python

And yet another possibility:

In [2]: a = array([1, 2, 3, -4, 5])

In [3]: where(a<0, 0, a)
Out[3]: array([1, 2, 3, 0, 5])

Solution 5 - Python

Here's a way to do it in Python without NumPy. Create a function that returns what you want and use a list comprehension, or the map function.

>>> a = [1, 2, 3, -4, 5]

>>> def zero_if_negative(x):
...   if x < 0:
...     return 0
...   return x
...

>>> [zero_if_negative(x) for x in a]
[1, 2, 3, 0, 5]

>>> map(zero_if_negative, a)
[1, 2, 3, 0, 5]

Solution 6 - Python

Benchmark using numpy:

%%timeit
a = np.random.random(1000) - 0.5
b = np.maximum(a,0)
# 18.2 µs ± 204 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
a = np.random.random(1000) - 0.5
a[a < 0] = 0
# 19.6 µs ± 304 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
%%timeit
a = np.random.random(1000) - 0.5
b = np.where(a<0, 0, a)
# 21.1 µs ± 134 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
a = np.random.random(1000) - 0.5
b = a.clip(0)
# 37.7 µs ± 124 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Supprisingly, np.maximum beat @NPE answer.


Caveat:

  1. os[os < 0] = 0 is faster than np.where() but not supported by numba. But whatever, np.maximum() is the fastest that I found.

  2. np.maximum() is different from np.max() and np.amax(). np.maximum() can compare vector with single value.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbphView Question on Stackoverflow
Solution 1 - PythonNPEView Answer on Stackoverflow
Solution 2 - PythonsenderleView Answer on Stackoverflow
Solution 3 - PythonLevonView Answer on Stackoverflow
Solution 4 - PythonRamon CrehuetView Answer on Stackoverflow
Solution 5 - PythonKekoaView Answer on Stackoverflow
Solution 6 - PythonMuhammad YasirroniView Answer on Stackoverflow