2

There is a nice way of finding the nonzero min/max of an array excluding zeros described in here:

import numpy as np
minval = np.min(a[np.nonzero(a)])
maxval = np.max(a[np.nonzero(a)])

However, this won't work as soon as a is a 2- or more dimensional array and an axis for the min/max is desired. Any simple solutions for that?

a.smiet
  • 1,727
  • 3
  • 21
  • 36
  • How close to zero is still zero if you are considering reals? A potentially important point to consider as well. – Jon Custer Mar 20 '18 at 21:12

2 Answers2

2

This is a non-vectorised approach. It can be vectorised by setting 0 values to a.min() / a.max() as separate steps.

import numpy as np

a = np.array([[1, 2, 0],
              [3, 1, 9],
              [0, 3, 4]])

minval = np.min(np.where(a==0, a.max(), a), axis=0)
# array([ 1.,  1.,  4.])

maxval = np.max(np.where(a==0, a.min(), a), axis=0)
# array([ 3.,  3.,  9.])
jpp
  • 159,742
  • 34
  • 281
  • 339
  • Set to `a.min(axis= )` and `a.max(axis= )` instead of Infs for keeping the dtypes. – Divakar Mar 20 '18 at 17:10
  • 1
    `np.min(np.where(a==0, a.max(), a), axis=0)` or `np.min(np.where(a==0, a.max(axis=0), a), axis=0)`. Similarly for the other one. – Divakar Mar 20 '18 at 17:13
0

Masked arrays are designed exactly for these kind of purposes. You can leverage masking zeros from array (or ANY other kind of mask you desire) and do pretty much most of the stuff you do on regular arrays on your masked array now:

import numpy.ma as ma
mx = ma.masked_array(x, mask=x==0)
mx.min(1)

Example input:

x = np.array([[3., 2., 0., 1., 6.], [8., 4., 5., 0., 6.], [0., 7., 2., 5., 0.]])

output:

[1.0 4.0 2.0]
Ehsan
  • 12,072
  • 2
  • 20
  • 33