Python 运行时警告:被零除错误:如何避免?巨蟒

Python 运行时警告:被零除错误:如何避免?巨蟒,python,numpy,Python,Numpy,我正在运行RuntimeWarning:在divide中遇到无效值 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

我正在运行RuntimeWarning:在divide中遇到无效值

 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 
我的a中有一些向量的范数为0。因此,在计算角度时,它会发出运行时警告

是否有一种单线python方法来计算角度,同时考虑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秒,这太疯狂了。

你可以用它来执行一个条件切片,其中标准值不等于0,然后再除以:

norms = np.where(norms != 0 ) 
angles = 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
s,而不是
nan
s

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])
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
这表明
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])
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

您可以使用
np.errstate
上下文管理器忽略警告,然后用所需内容替换NAN:

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

您想使用
np.where
。看


只要
标准!=0,否则将为-2。您仍然会得到RuntimeWarning,如
np。其中
仍将在内部计算整个向量
点/规范
,但您可以安全地忽略它。

在较新版本的numpy中,有第三个替代选项,可以避免使用errstate上下文管理器

所有Numpy都接受可选的“where”参数。这与np.where函数的作用稍有不同,因为它只计算掩码为true的函数“where”。当掩码为False时,它不会更改值,因此使用“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)

范数是向量而不是数字。我想对向量进行元素级的除法,在不可能除法的地方加上None,你能在通过之前过滤范数吗?不,我想保留索引,因为我想在最后加上10个最大角度的索引,在其他列表中进一步匹配。因此,我必须保留索引。对于您发布的代码,
angles
变量将具有nan,其中
norms
为零。这不是你想要的吗?请注意,如果希望
None
而不是
NaN
,则需要对dtype
对象
进行
角度
,这对性能不利。。。(另外,也可以只抑制运行时警告。这是您想要的吗?)我想要在遇到NaN的地方有特定的值。因此,我可以在排序时对其进行操作。nans排序比任何其他排序都高,因此,在排序时,您只需将顶部的np.count_去除为非零(np.isnan(d.ravel())值我的代码一直在说:numpy.ndarray没有属性where.WTF?where是numpy中的一个函数,它不是ndarray的一个坏方法..我应该继续工作。谢谢你的帮助!!不知何故它没有给我任何警告!!如果你以交互方式运行python(例如在ipython中)那么我相信每次会话它只会给你一次警告。你也可以按照jtaylor的建议添加
np.errstate(divide='ignore')
,以在将来抑制警告。