问题
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