Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

avoid division by zero in numpy.where()

Tags:

python

numpy

I have two numpy arrays a, b of the same shape, b has a few zeros. I would like to set an output array to a / b where b is not zero, and a otherwise. The following works, but yields a warning because a / b is computed everywhere first.

import numpy

a = numpy.random.rand(4, 5)
b = numpy.random.rand(4, 5)
b[b < 0.3] = 0.0

A = numpy.where(b > 0.0, a / b, a)
/tmp/l.py:7: RuntimeWarning: divide by zero encountered in true_divide
  A = numpy.where(b > 0.0, a / b, a)

Filtering the division with a mask doesn't perserve the shape, so this doesn't work:

import numpy

a = numpy.random.rand(4, 5)
b = numpy.random.rand(4, 5)
b[b < 0.3] = 0.0

mask = b > 0.0
A = numpy.where(mask, a[mask] / b[mask], a)
ValueError: operands could not be broadcast together with shapes (4,5) (14,) (4,5)

Any hints on how to avoid the warning?

like image 336
Nico Schlömer Avatar asked Aug 28 '20 08:08

Nico Schlömer


People also ask

How do I stop dividing by zero in Python?

In Python, we use a try block that contains a return statement to divide 2 numbers. If there is no division by zero error, then it will return the result. Otherwise, the except line will check if the specified exception name is a match, and then it will execute the code under the except block.

How does NumPy handle division by zero?

Behavior on division by zero can be changed using seterr. When both x1 and x2 are of an integer type, divide will return integers and throw away the fractional part. Moreover, division by zero always yields zero in integer arithmetic.

What is the zero () function in NumPy use to?

Python numpy. zeros() function returns a new array of given shape and type, where the element's value as 0.

How can we avoid ZeroDivisionError float division by zero?

The Python "ZeroDivisionError: float division by zero" occurs when we try to divide a floating-point number by 0 . To solve the error, use an if statement to check if the number you are dividing by is not zero, or handle the error in a try/except block.


1 Answers

Simply initialize output array with the fallback values (condition-not-satisfying values) or array and then mask to select the condition-satisfying values to assign -

out = a.copy()
out[mask] /= b[mask]

If you are looking for performance, we can use a modified b for the division -

out = a / np.where(mask, b, 1)

Going further, super-charge it with numexpr for this specific case of positive values in b (>=0) -

import numexpr as ne
    
out = ne.evaluate('a / (1 - mask + b)')

Benchmarking

enter image description here

Code to reproduce the plot:

import perfplot
import numpy
import numexpr

numpy.random.seed(0)


def setup(n):
    a = numpy.random.rand(n)
    b = numpy.random.rand(n)
    b[b < 0.3] = 0.0
    mask = b > 0
    return a, b, mask


def copy_slash(data):
    a, b, mask = data
    out = a.copy()
    out[mask] /= b[mask]
    return out


def copy_divide(data):
    a, b, mask = data
    out = a.copy()
    return numpy.divide(a, b, out=out, where=mask)


def slash_where(data):
    a, b, mask = data
    return a / numpy.where(mask, b, 1.0)


def numexpr_eval(data):
    a, b, mask = data
    return numexpr.evaluate('a / (1 - mask + b)')


b = perfplot.bench(
    setup=setup,
    kernels=[copy_slash, copy_divide, slash_where, numexpr_eval],
    n_range=[2 ** k for k in range(24)],
    xlabel="n"
)
b.save("out.png")
like image 183
Divakar Avatar answered Sep 20 '22 21:09

Divakar