运行时警告:如何避免除零错误?PYTHON, NUMPY
我遇到了一个运行时警告:在除法中遇到了无效值。
import numpy
a = numpy.random.rand((1000000, 100))
b = numpy.random.rand((1,100))
dots = numpy.dot(b,a.T)/numpy.dot(b,b)
norms = numpy.linalg.norm(a, axis =1)
angles = dots/norms ### Basically I am calculating angle between 2 vectors
我的一些向量的长度是0,所以在计算角度时就出现了这个运行时警告。
有没有一种简单的一行代码的方式,可以在计算角度时考虑到长度为0的情况呢?
angles =[i/j if j!=0 else -2 for i,j in zip(dots, norms)] # takes 10.6 seconds
不过这样做耗时很长。因为所有的角度值都在1到-1之间,而我只需要最大的10个值,这样可以帮到我。这个过程大约需要10.6秒,真是太慢了。
5 个回答
你可以使用 np.where( condition )
来选择那些不等于0的数值,然后再进行除法运算:
norms = np.where(norms != 0 )
angles = dots/norms
你应该使用 np.where
这个函数。具体的用法可以参考 这个文档。
angles = np.where(norms != 0, dots/norms, -2)
在计算角度的时候,当 norms
不等于 0 时,结果会是 downs/norms
,如果 norms
等于 0,则结果会是 -2。虽然你会看到一个运行时警告(RuntimeWarning),因为 np.where
还是会内部计算整个向量 dots/norms
,但这个警告可以安全地忽略。
你可以用 angles[~np.isfinite(angles)] = ...
这个方法,把 nan
值替换成其他的值。
比如说:
In [103]: angles = dots/norms
In [104]: angles
Out[104]: array([[ nan, nan, nan, ..., nan, nan, nan]])
In [105]: angles[~np.isfinite(angles)] = -2
In [106]: angles
Out[106]: array([[-2., -2., -2., ..., -2., -2., -2.]])
要注意的是,除以零可能会得到 inf
,而不是 nan
,
In [140]: np.array([1, 2, 3, 4, 0])/np.array([1, 2, 0, -0., 0])
Out[140]: array([ 1., 1., inf, -inf, nan])
所以最好用 np.isfinite
来找出那些因为除以零而出现的问题,而不是用 np.isnan
。
In [141]: np.isfinite(np.array([1, 2, 3, 4, 0])/np.array([1, 2, 0, -0., 0]))
Out[141]: array([ True, True, False, False, False], dtype=bool)
另外,如果你只想从一个 NumPy 数组中获取前十个值,使用 np.argpartition
函数可能会比把整个数组完全排序要快,尤其是对于很大的数组:
In [110]: N = 3
In [111]: x = np.array([50, 40, 30, 20, 10, 0, 100, 90, 80, 70, 60])
In [112]: idx = np.argpartition(-x, N)
In [113]: idx
Out[113]: array([ 6, 7, 8, 9, 10, 0, 1, 4, 3, 2, 5])
In [114]: x[idx[:N]]
Out[114]: array([100, 90, 80])
这表明即使是对于中等大小的数组,np.argpartition
也会更快:
In [123]: x = np.array([50, 40, 30, 20, 10, 0, 100, 90, 80, 70, 60]*1000)
In [124]: %timeit np.sort(x)[-N:]
1000 loops, best of 3: 233 µs per loop
In [125]: %timeit idx = np.argpartition(-x, N); x[idx[:N]]
10000 loops, best of 3: 53.3 µs per loop
在较新版本的numpy中,有一个第三种选择,可以避免使用errstate上下文管理器。
所有的Numpy ufuncs都接受一个可选的“where”参数。这个参数的作用和np.where函数有点不同,它只在条件为真的地方计算函数。当条件为假时,它不会改变值,因此使用“out”参数可以让我们提前设置任何我们想要的默认值。
import numpy as np
angle = np.arange(-5., 5.)
norm = np.arange(10.)
# version 1
with np.errstate(divide='ignore'):
res1 = np.where(norm != 0., angle / norm, -2)
# version 2
with np.errstate(divide='ignore'):
res2 = angle/norm
res2[np.isinf(res2)] = -2
# version 3
res3 = -2. * np.ones(angle.shape)
np.divide(angle, norm, out=res3, where=norm != 0)
print(res1)
print(res2)
print(res3)
np.testing.assert_array_almost_equal(res1, res2)
np.testing.assert_array_almost_equal(res1, res3)
你可以使用 np.errstate
这个上下文管理器来忽略警告,之后再把那些“不是数字”(nans)替换成你想要的值:
import numpy as np
angle = np.arange(-5., 5.)
norm = np.arange(10.)
with np.errstate(divide='ignore'):
print np.where(norm != 0., angle / norm, -2)
# or:
with np.errstate(divide='ignore'):
res = angle/norm
res[np.isnan(res)] = -2