Pietro Speroni
Pietro Speroni

Reputation: 3221

Division with numpy matrices that might result in nan

How can I divide two numpy matrices A and B in python when sometimes the two matrices will have 0 on the same cell?

Basically A[i,j]>=B[i,j] for all i, j. I need to calculate C=A/B. But sometimes A[i,j]==B[i,j]==0. And when this happens I need A[i,j]/B[i,j] to be defined as 0.

Is there a simple pythonic way other than going through all the indexes?

Upvotes: 4

Views: 6339

Answers (2)

MSeifert
MSeifert

Reputation: 152587

You can use the where argument for ufuncs like np.true_divide:

np.true_divide(A, B, where=(A!=0) | (B!=0))

In case you have no negative values (as stated in the comments) and A >= B for each element (as stated in the question) you can simplify this to:

np.true_divide(A, B, where=(A!=0))

because A[i, j] == 0 implies B[i, j] == 0.


For example:

import numpy as np
A = np.random.randint(0, 3, (4, 4))
B = np.random.randint(0, 3, (4, 4))
print(A)
print(B)
print(np.true_divide(A, B, where=(A!=0) | (B!=0)))

[[1 0 2 1]
 [1 0 0 0]
 [2 1 0 0]
 [2 2 0 2]]

[[1 0 1 1]
 [2 2 1 2]
 [2 1 0 1]
 [2 0 1 2]]

[[ 1.   0.   2.   1. ]
 [ 0.5  0.   0.   0. ]
 [ 1.   1.   0.   0. ]
 [ 1.   inf  0.   1. ]]

As alternative: Just replace nans after the division:

C = A / B          # may print warnings, suppress them with np.seterrstate if you want
C[np.isnan(C)] = 0

Upvotes: 4

Divakar
Divakar

Reputation: 221504

You could use a mask with np.where to choose between such a case of A and B being both zeros and otherwise and put out 0 or an elementwise division respectively -

from __future__ import division # For Python 2.x

mask = (A == B) & (A==0)
C = np.where(mask, 0, A/B)

About the mask creation : (A==B) would be the mask of all elements that are equal between A and B and with (A==0) we have a mask of all elements that are zero in A. Thus, with a combined mask of (A == B) & (A==0), we have mask of places where both A and B are zeros. A more simpler version to do the same task and maybe easier to understand would be to check for zeros in both A and B and it would be :

mask = (A==0) & (B==0)

About the use of np.where, its syntax is :

C = np.where(mask, array1, array2)

i.e. we would select elements for assinging into C based on the mask. If the corresponding mask element is True, we pick the corresponding element from array1, else from array2. This is done on elementwise level and thus, we have the output C.

Sample run -

In [48]: A
Out[48]: 
array([[4, 1, 4, 0, 3],
       [0, 4, 1, 4, 3],
       [1, 0, 0, 4, 0]])

In [49]: B
Out[49]: 
array([[4, 2, 2, 1, 4],
       [2, 1, 2, 4, 2],
       [4, 0, 2, 0, 3]])

In [50]: mask = (A == B) & (A==0)

In [51]: np.where(mask, 0, A/B)
Out[51]: 
array([[ 1.  ,  0.5 ,  2.  ,  0.  ,  0.75],
       [ 0.  ,  4.  ,  0.5 ,  1.  ,  1.5 ],
       [ 0.25,  0.  ,  0.  ,   inf,  0.  ]])

Upvotes: 2

Related Questions