0

I wish to divide an array numerators by an array denominators, but some elements in denominators may be zero. The resulting element at those indices should be zero as well. Is there a function in NumPy which picks elements from numerators / denominators where denominators isn't zero, and from a zero array otherwise?

I looked into boolean masking, but that would take multiple lines, since I would have to mask denominators in order to not get any division-by-zero errors, as well as the result in order to set those elements to zero.

I could swear I've seen such a function but I can't find it anymore.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
  • 2
    [`np.where`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html)? – jdehesa Jun 05 '19 at 10:56
  • np.where and np.divide have some issues; refer to this https://stackoverflow.com/questions/26248654/how-to-return-0-with-divide-by-zero for an answer – PeptideWitch Jun 05 '19 at 11:27

3 Answers3

1

Take a look at np.divide. You can use a condition on your denominator array in the where parameter to put a condition on the division: where=denominators!=0. This will keep the value of the first array, however.

You can ommit the where parameter all together, which gives a warning and a 0 in the place where the denominator was 0.

You can also create a zeros array (np.zeros(shape)) and give that as array to which the divide method should write its result. In combination with the where parameter, this will give the correct result without a warning.

SBylemans
  • 1,764
  • 13
  • 28
1

You have a number of options available:

  1. Ufuncs like np.divide support a where mask as of numpy version 1.7:

    quotients = np.divide(numerators, denominators, out=np.zeros(np.broadcast(numerators, denominators).shape, where=denominators != 0)
    
  2. Use masked arrays:

    quotients = (numerators / np.ma.array(denominators, mask=denominators)).data
    

    This masks all elements of denominators that are zero, performs the division without changing them, and extracts the unmasked array.

  3. Use masking by hand. This will be more than one line, but you can turn it into a function for future use:

    quotients = np.zeros(np.broadcast(numerators, denominators).shape)
    mask = ~denominators
    quotients[mask] = numerators[mask] / denominators[mask]
    

    OR

    quotients = np.empty(np.broadcast(numerators, denominators).shape)
    mask = ~denominators
    quotients[mask] = numerators[mask] / denominators[mask]
    quotients[mask] = 0
    

The knee-jerk response to use np.where does not work in this case. You end up pre-computing numerators / denominators, as in np.where(denominators, numerators / denominators, 0), which defeats the entire purpose. Alternatively, you end up replacing the mask with np.where(denominators), but at that point a mask is more efficient.

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
0
inds = np.where(denominators!=0)
ratio = np.zeros(numerators.shape)
ratio[inds] = nominators[inds]/denominators[inds]

Or, even more compact version:

np.where(denominators!=0,nominators/denominators,0)

The second approach gives what you want, but raises RuntimeWarning. You'll still get the desired values, though.

pmarcol
  • 453
  • 2
  • 9