I have an array. The valid values are not zero (either positive or negetive). I want to find the minimum and maximum within the array which should not take zeros into account. For example if the numbers are only negative. Zeros will be problematic.
-
4What is your question? What have you tried? How didn't it work? – hmakholm left over Monica Aug 23 '11 at 16:36
6 Answers
How about:
import numpy as np
minval = np.min(a[np.nonzero(a)])
maxval = np.max(a[np.nonzero(a)])
where a
is your array.

- 66,734
- 27
- 141
- 140
-
3@Shan: Using masked arrays can avoid the copy created by `a[np.nonzero(a)]` -- see my answer. – Sven Marnach Aug 23 '11 at 16:58
If you can choose the "invalid" value in your array, it is better to use nan
instead of 0
:
>>> a = numpy.array([1.0, numpy.nan, 2.0])
>>> numpy.nanmax(a)
2.0
>>> numpy.nanmin(a)
1.0
If this is not possible, you can use an array mask:
>>> a = numpy.array([1.0, 0.0, 2.0])
>>> masked_a = numpy.ma.masked_equal(a, 0.0, copy=False)
>>> masked_a.max()
2.0
>>> masked_a.min()
1.0
Compared to Josh's answer using advanced indexing, this has the advantage of avoiding to create a copy of the array.

- 574,206
- 118
- 941
- 841
-
-
+1 Masked arrays are another nice (and often under utilized) solution – JoshAdel Aug 23 '11 at 17:05
-
2@Sven: when I do `ma.base is a` I get false, so it doesn't look like `ma` is just a view of `a` and there is a copy of the memory somewhere. Or am I testing this the wrong way? – JoshAdel Aug 23 '11 at 17:12
-
2@JoshAdel: by default, [np.ma.masked_equal](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ma.masked_equal.html#numpy.ma.masked_equal) makes a copy of `a`. To get a view, use `ma = np.ma.masked_equal(a, 0.0, copy=False)`. – unutbu Aug 26 '11 at 13:14
-
1This worked perfectly for me - I had a case where I needed to retrieve the index of the min/max nonzero value. – Wojciech Migda Sep 01 '15 at 19:45
-
I know this is a really old post, but thank you. I wanted to add that if you are working with a column from a pandas imported csv, you must convert the column to an array before the masking will work. As a total python noob, this answer really spoke to me. – Patrick Williams Apr 29 '16 at 05:12
-
-
1Just a side comment: I feel like naming the view (`ma`) same as the module used to create it (`numpy.ma`) is unnecessarily confusing for someone trying to understand this code, when it could have been named literally anything else more descriptive. Why not `a_view`, for example?? – Brunox13 Jul 17 '20 at 16:08
-
1@Brunox13 It wouldn't have occurred to me that this is confusing, since it's just three lines of code, so thanks for the feedback! I went with `masked_a`. – Sven Marnach Jul 17 '20 at 18:51
-
Here's another way of masking which I think is easier to remember (although it does copy the array). For the case in point, it goes like this:
>>> import numpy
>>> a = numpy.array([1.0, 0.0, 2.0])
>>> ma = a[a != 0]
>>> ma.max()
2.0
>>> ma.min()
1.0
>>>
It generalizes to other expressions such as a > 0, numpy.isnan(a), ... And you can combine masks with standard operators (+ means OR, * means AND, - means NOT) e.g:
# Identify elements that are outside interpolation domain or NaN
outside = (xi < x[0]) + (eta < y[0]) + (xi > x[-1]) + (eta > y[-1])
outside += numpy.isnan(xi) + numpy.isnan(eta)
inside = -outside
xi = xi[inside]
eta = eta[inside]

- 171
- 1
- 2
Masked arrays in general are designed exactly for these kind of purposes. You can leverage masking zeros from an array (or ANY other kind of mask you desire, even masks that are more complicated than a simple equality) and do pretty much most of the stuff you do on regular arrays on your masked array. You can also specify an axis for which you wish to find the min along:
import numpy.ma as ma
mx = ma.masked_array(x, mask=x==0)
mx.min()
Example input:
x = np.array([1.0, 0.0, 2.0])
output:
1.0

- 12,072
- 2
- 20
- 33
You could use a generator expression to filter out the zeros:
array = [-2, 0, -4, 0, -3, -2]
max(x for x in array if x != 0)

- 2,822
- 1
- 14
- 7
-
1I think the OP is talking about numpy arrays and not python lists. There is a difference, although your solution is correct for the later. Not going to downvote, but just so you know. – JoshAdel Aug 23 '11 at 16:39
-
-
1This still works on numpy arrays, so it's a valid answer. For small arrays like this, it's significantly faster than the numpy version, too. – endolith Sep 01 '19 at 03:48
A simple way would be to use a list comprehension to exclude zeros.
>>> tup = (0, 1, 2, 5, 2)
>>> min([x for x in tup if x !=0])
1

- 13,822
- 10
- 58
- 90
-
1
-
didn't see tuple in the title and only read the question which says array. I stand corrected +1. I jumped on you (and the other response), because people post solutions to numpy questions treating them as if they are numpy lists, which they aren't. It's a personal pet peeve, since the numpy solution is often wildly more efficient. – JoshAdel Aug 23 '11 at 16:44
-
slight correction of what I wrote above: '....treating them as if they are **python** lists...' – JoshAdel Aug 23 '11 at 16:56