0

I've noticed that the RuntimeWarning: divide by zero encountered in log warnings gets triggered for masked arrays as well.

Consider the following two examples:

Regular arrays

>>> import numpy as np
>>> y = np.zeros((3,3)) + np.eye(3,3)
>>> np.log(y)
<stdin>:1: RuntimeWarning: divide by zero encountered in log
array([[  0., -inf, -inf],
       [-inf,   0., -inf],
       [-inf, -inf,   0.]])

Masked arrays

>>> import numpy as np
>>> y = np.zeros((3,3)) + np.eye(3,3)
>>> y_mask = np.ma.masked_equal(y, 0)
>>> np.log(y_mask)
<stdin>:1: RuntimeWarning: divide by zero encountered in log
masked_array(
  data=[[0.0, --, --],
        [--, 0.0, --],
        [--, --, 0.0]],
  mask=[[False,  True,  True],
        [ True, False,  True],
        [ True,  True, False]],
  fill_value=0.0)

Is this the expected behaviour? I would have expected the log operation to only happen on the non zero values in the case of masked arrays.

Additionally I have noticed that the this warning only gets triggered once per session. Any subsequent calls to the log function whether on masked or regular arrays won't trigger this warning.

I could suppress this warning via numpy.seterr(divide = 'ignore') but I'm curious as to why the operation on masked arrays raises a warning in the first place.

ashnair1
  • 345
  • 2
  • 9
  • `ma` does the math on all elements; masking is applied to the result. Use the `where` and `out` parameters of `np.log` if you want to skip the 0s. – hpaulj Aug 08 '22 at 06:49
  • Just observed that using `np.ma.log` does not output the warning. – ashnair1 Aug 08 '22 at 07:00
  • It is best to use `np.ma` versions of `ufunc` where available. The generic versions may not handle masked elements correctly. – hpaulj Aug 08 '22 at 07:01
  • 1
    I explained this 5 yrs ago (but code details could have changed), https://stackoverflow.com/questions/46983061/operations-on-numpy-masked-array-gives-invalid-values-masked – hpaulj Aug 08 '22 at 07:10

1 Answers1

1

np.ma versions of numpy functions can do one of several things.

  1. use compress to operate on just the unmasked values,

  2. use fill to replace masked elements with something like 1 or 0,

  3. use errstate to surpress the warnings. np.ma.log uses the surpress method

Source for np.ma.log is

Signature:       np.ma.log(a, *args, **kwargs)
Type:            _MaskedUnaryOperation
String form:     Masked version of <ufunc 'log'>
File:            /usr/local/lib/python3.8/dist-packages/numpy/ma/core.py
Source:         
class _MaskedUnaryOperation(_MaskedUFunc):
    """
    Defines masked version of unary operations, where invalid values are
    pre-masked.
    ...
    def __call__(self, a, *args, **kwargs):
    ...
         with np.errstate(divide='ignore', invalid='ignore'):
                result = self.f(d, *args, **kwargs)

Previously

Operations on numpy masked array gives invalid values masked

hpaulj
  • 221,503
  • 14
  • 230
  • 353