我将以下代码作为函数的一部分:
px = x2 - x1
py = y2 - y1
pz = z2 - z1
div = px*px + py*py
u = ((x0 - x1) * px + (y0 - y1) * py) / div
u=
行在运行时返回RuntimeWarning: invalid value encountered in divide
。这是因为偶尔div=
行返回零。
但是,如果我将u=
行重写为:
u = np.where(div != 0, ((x0 - x1) * px + (y0 - y1) * py) / div, 0)
它仍会返回相同的运行时警告。
此代码输出所需的数字,但我认为np.where
函数是懒惰的。如果不是这种情况,那么我写的其他代码中有可能加速(因此我问这个问题)。
我错过了什么? np.where
函数是否计算'True'和'False输入,然后根据布尔值选择一个?
请注意,这是我最终得到的解决方案:
np.seterr(invalid='ignore')
u = np.where(div != 0, ((x0 - x1) * px + (y0 - y1) * py) / div, 0)
np.seterr(invalid='warn')
虽然这也很好:
u = np.zeros_like(div)
divb = div != 0
u[divb] = ((x0[divb] - x1[divb]) * px[divb] +
(y0[divb] - y1[divb]) * py[divb]) / div[divb]
(这是我认为的np.where
所做的......)
这两种解决方案的速度大致相同,但两者都比np.where
函数慢。
欢迎任何解释/建议! 感谢。
答案 0 :(得分:2)
自从最早的矢量化语言(例如APL,MATLAB)以来,程序员一直在努力解决这个问题。
我过去使用的一个解决方案是(有条件地)将1加到除数中:
u = ((x0 - x1) * px + (y0 - y1) * py) / (div + (div==0))
它并非在所有情况下都有效,但可能在此情况下,因为只有当div
和px
都为0时,py
才会显示为0。在这种情况下分子也是0. 0/1 = 0
。
使用较小的值剪切div
(这可能是最快的解决方案):
..../np.maximum(div,1e-16)
对numpy divide by zero
的SO快速搜索发现了其他问题。例如:
https://stackoverflow.com/a/26248892/901925
建议使用errstate
上下文关闭警告:
with numpy.errstate(divide='ignore'):
u = .../div
divide
适用于1/0
等案件,invalid
案件需要0/0
。但ignore
最终会将inf
或nan
放入返回数组中。因此,您仍需要测试(div==0)
以获得0
值。
虽然我更喜欢这种形式的外观:
with np.errstate(invalid='ignore'):
u = np.where(div==0, 0, .../div)
沃伦的评论解释了为什么where
不起作用。参数在传递给函数之前进行求值。延迟评估需要Python解释器的合作。它通常是语法的一部分(例如if
,|
,&
)。