How to multiply.outer() in NumPy while assuming 0 * infinity = 0?

别说谁变了你拦得住时间么 提交于 2019-12-12 18:44:09

问题


I'm trying to use numpy.multiply.outer on multidimensional arrays, and I really need it to assume that any 0 * infinity it sees evaluates to zero. How can I do this efficiently?

>>> import numpy
>>> numpy.multiply.outer([0.], [float('inf')])
Warning (from warnings module):
  File "__main__", line 2
RuntimeWarning: invalid value encountered in multiply
array([[ nan]])

回答1:


Do you need to worry about other sources of nan values? If not, you could always just fix up in a separate step:

import numpy as np

r = np.multiply.outer([0.], [float('inf')])
np.where(np.isnan(r), 0, r)

Up to you if you want to suppress the warnings.




回答2:


One solution could be to avoid using np.multiply.outer and find the solution using element-wise multiplication on matrices that have already been checked to see if they meet the condition of interest (zero in one array, inf in other array).

import numpy as np
A = np.array([0., 0., 0.4, 2])
B = np.array([float('inf'), 1., 3.4, np.inf])

# Conditions of interest
c1 = (A == 0)
c2 = (B == np.inf)
condition1 = np.multiply.outer(c1, c2)
c3 = (A == np.inf)
c4 = (B == 0)
condition2 = np.multiply.outer(c3, c4)
condition = condition1 | condition2

AA = np.multiply.outer(A, np.ones(B.shape))
BB = np.multiply.outer(np.ones(A.shape), B)

AA[condition] = 0.
BB[condition] = 0.

AA*BB

This may not pass the 'efficiency' request of the poster, however.




回答3:


Here's how to suppress the warnings:

mean, nanmean and warning: Mean of empty slice

In [528]: import warnings

In [530]: x = np.array([0,1,2],float)
In [531]: y = np.array([np.inf,3,2],float)
In [532]: np.outer(x,y)
/usr/local/lib/python3.5/dist-packages/numpy/core/numeric.py:1093: RuntimeWarning: invalid value encountered in multiply
  return multiply(a.ravel()[:, newaxis], b.ravel()[newaxis,:], out)
Out[532]: 
array([[ nan,   0.,   0.],
       [ inf,   3.,   2.],
       [ inf,   6.,   4.]])

In [535]: with warnings.catch_warnings():
     ...:     warnings.simplefilter('ignore',category=RuntimeWarning)
     ...:     z = np.outer(x,y)
     ...:     
In [536]: z
Out[536]: 
array([[ nan,   0.,   0.],
       [ inf,   3.,   2.],
       [ inf,   6.,   4.]])

replace the nan with 1:

In [542]: z[np.isnan(z)]=1
In [543]: z
Out[543]: 
array([[  1.,   0.,   0.],
       [ inf,   3.,   2.],
       [ inf,   6.,   4.]])

In [547]: z[np.isinf(z)]=9999
In [548]: z
Out[548]: 
array([[  1.00000000e+00,   0.00000000e+00,   0.00000000e+00],
       [  9.99900000e+03,   3.00000000e+00,   2.00000000e+00],
       [  9.99900000e+03,   6.00000000e+00,   4.00000000e+00]])

=================

We could create a mask using the kind of testing that @P-robot demonstrates:

In [570]: np.outer(np.isinf(x),y==0)|np.outer(x==0,np.isinf(y))
Out[570]: 
array([[ True, False, False],
       [False, False, False],
       [False, False, False]], dtype=bool)
In [571]: mask=np.outer(np.isinf(x),y==0)|np.outer(x==0,np.isinf(y))
In [572]: with warnings.catch_warnings():
     ...:     warnings.simplefilter('ignore',category=RuntimeWarning)
     ...:     z = np.outer(x,y)
     ...:     
In [573]: z[mask]=1
In [574]: z
Out[574]: 
array([[  1.,   0.,   0.],
       [ inf,   3.,   2.],
       [ inf,   6.,   4.]])

Or with messier inputs:

In [587]: x = np.array([0,1,2,np.inf],float)
In [588]: y = np.array([np.inf,3,np.nan,0],float)
In [589]: mask=np.outer(np.isinf(x),y==0)|np.outer(x==0,np.isinf(y))
...
In [591]: with warnings.catch_warnings():
     ...:     warnings.simplefilter('ignore',category=RuntimeWarning)
     ...:     z = np.outer(x,y)
     ...:     
In [592]: z[mask]=1
In [593]: z
Out[593]: 
array([[  1.,   0.,  nan,   0.],
       [ inf,   3.,  nan,   0.],
       [ inf,   6.,  nan,   0.],
       [ inf,  inf,  nan,   1.]])



回答4:


While I agree that @ShadowRanger's answer, a cheap hack could be to take advantage of np.nan_to_num, which replaces infs with large finite numbers, which will then get you inf * 0 = 0.

To convert unwanted remaining high finite numbers back to inf (given some other operations besides your question) you can use multiple the high number by anything > 1 and then divide by the same amount (so as not to impact other numbers). E.g.:

In [1]: np.nan_to_num(np.inf)
Out[1]: 1.7976931348623157e+308

In [2]: np.nan_to_num(np.inf)*1.1
RuntimeWarning: overflow encountered in double_scalars
Out[2]: inf

In [3]: np.nan_to_num(np.inf)*1.1/1.1
RuntimeWarning: overflow encountered in double_scalars
Out[3]: inf

Before the flood of downvotes, this is clearly not a best practice, and can potentially have side effects depending on your use case, but just thought I'd throw an alternative out there.



来源:https://stackoverflow.com/questions/41070766/how-to-multiply-outer-in-numpy-while-assuming-0-infinity-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!