[PYTHON] [Numpy] Avoid division by zero warning

I was at a loss when writing the program myself, so I will write it down as a memo. If you know a better solution, please point it out.

※environment

numpy division by zero

When I do normal division by zero in Python, I get a ZeroDivisionError.

python


try:
    divided = 1 / 0
except ZeroDivisionError as e:
    print(f'ZeroDivisionError: {e}')

# -> ZeroDivisionError: division by zero

On the other hand, if you divide by zero with numpy, RuntimeWarning will occur, but the result will be output without stopping the processing.

python


import numpy as np

divided = 1 / np.array(0)
print(devided)
# -> inf
# -> RuntimeWarning: divide by zero encountered in true_divide

The result of the calculation of 1 / np.array (0) is the object numpy.inf which represents infinity with numpy. It gives a warning, but it doesn't stop the process, so it feels halfway. Perhaps it is left to the user to say, "I can calculate it, but I'll give you a warning. I'll leave it to you." So, let's think about what to do when you want to stop the process and when you allow the process and ignore the warning.

Use warnings.simplefilter

You can use warnings.simplefilter to make RuntimeWarning an exception or ignore it.

--When you want to treat it as an exception and stop processing

python


import warnings
import numpy as np
warnings.simplefilter('error', category=RuntimeWarning)  #Set Runtime Warning as exception

a = np.array(0)  #Variables that are not expected to contain 0
divided = 1 / a
print(divided)

# -> RuntimeWarning: divide by zero encountered in true_divide
# divided = 1 /Processing stops at a and print(divided)Is not executed

--When you want to allow calculations and ignore warnings

python


import warnings
import numpy as np
warnings.simplefilter('ignore', category=RuntimeWarning)  #Set Runtime Warning to ignore

a = np.array(0)  #Variables that may contain 0
divided = 1 / a
print(divided)

# -> inf
#No warning is issued and processing continues

However, at this time, the control is applied to RuntimeWarning other than division by zero, so there is a risk that the bug cannot be captured, especially if it is ignored. So I think about another method

Use numpy.seteer

(In response to the comment, I added numpy.seteer.) You can use numpy.seteer to set finer control of Warning.

python


import numpy as np
np.seterr(divide='ignore')  #Ignore only Division by Zero Runtime Warning

a = np.array(0)
divided = 1 / a
print(divided)

# -> inf

Now you can add control only to division by zero. The complexity of ʻimporting warningshas also been eliminated. However, in this case this control applies to the entire source code. If possible, I want to minimize the scope of control. You can switch the control by writingnumpy.seterr` before and after division, but consider a smarter description.

Use numpy.errstate

(This is also the part added from the comments pointed out)

By using numpy.errstate, it is possible to control by the context manager.

python


import numpy as np

a = np.array(0) 
with np.errstate(divide='ignore'):  #Apply control only within scope
    divided = 1 / a
print(divided)
# -> inf

divided = 1 / a  #Runtime Warning occurs because it is out of scope for ignoring
# -> RuntimeWarning: divide by zero encountered in true_divide

This will reduce the scope of control changes and supplement bugs caused by division by zero elsewhere (not allowed).

In the example, we considered division of numbers for clarity, but you can control array division as well.

python


import numpy as np

a = np.array([1, 2, 0]) 
with np.errstate(divide='ignore'):  #Apply control only within scope
    divided = 1 / a
print(divided)
# -> [1.  0.5 inf]

If you want to divide one number, you can simply write an if statement, but in the case of an array, that is difficult, so I think this control method will be useful.

bonus

At first, I didn't know numpy.errstate and thought about how to write it as follows.

python


import numpy as np

a = np.array([1, 2, 0])
divided = np.full(len(a), np.inf)  #All elements are np.Make an array of inf
nonzero_indices = np.where(a != 0)[0]  #An array of indexes with non-zero elements in a
divided[nonzero_indices] = 1 / a[nonzero_indices]  # nonzero_Rewrite only the elements of array to division

print(divided)
# -> [1.  0.5 inf]

I wanted to avoid the warning of division by zero only, but it seems redundant. I want to be able to remember and use useful methods like numpy.errstate.

Recommended Posts

[Numpy] Avoid division by zero warning
Avoid the warning [invalid value encountered in true_divide] when dividing by zero