【问题标题】:Numpy "Where" function can not avoid evaluate Sqrt(negative)Numpy“Where”函数无法避免评估Sqrt(负)
【发布时间】:2020-05-20 21:03:32
【问题描述】:

似乎np.where 函数首先评估所有可能的结果,然后再评估条件。这意味着,在我的例子中,它将计算 -5、-4、-3、-2、-1 的平方根,即使它以后不会使用。

我的代码运行正常。但我的问题是警告。我避免使用循环来评估每个元素,因为它的运行速度比np.where 慢得多。

所以,我在这里问

  1. 有什么方法可以让np.where首先评估条件吗?
  2. 我可以只关闭这个特定的警告吗?怎么样?
  3. 如果您有更好的建议,另一种更好的方法。

这里只是一个简短的示例代码,对应于我的真实代码,它是巨大的。但本质上也有同样的问题。

输入:

import numpy as np

c=np.arange(10)-5
d=np.where(c>=0, np.sqrt(c) ,c )

输出:

RuntimeWarning: invalid value encountered in sqrt
d=np.where(c>=0,np.sqrt(c),c)

【问题讨论】:

  • 根据 numpy documentation,声明 d=np.where(c>=0, np.sqrt(c) ,c ) 等价于 [sqcv if cond else cv for (cond, sqcv, cv) in zip(c>=0, np.sqrt(c), c)]。换句话说,无论c>=0 条件如何,都会评估术语np.sqrt(c)

标签: python numpy


【解决方案1】:

有一个很多更好的方法来做到这一点。让我们看看你的代码在做什么,看看为什么。

np.where 接受三个数组作为输入。数组不支持惰性求值。

d = np.where(c >= 0, np.sqrt(c), c)

因此这一行相当于做

a = (c >= 0)
b = np.sqrt(c)
d = np.where(a, b, c)

请注意,在调用 where 之前会立即计算输入。

幸运的是,您根本不需要使用where。相反,只需使用布尔掩码:

mask = (c >= 0)
d = np.empty_like(c)
d[mask] = np.sqrt(c[mask])
d[~mask] = c[~mask]

如果您预计会有很多负面因素,您可以复制所有元素,而不仅仅是负面因素:

d = c.copy()
d[mask] = np.sqrt(c[mask])

更好的解决方案可能是使用掩码数组:

d = np.ma.masked_array(c, c < 0)
d = np.ma.sqrt(d)

要访问整个数据数组,且屏蔽部分保持不变,请使用d.data

【讨论】:

  • 嗨,谢谢。它运作良好。但是当我尝试你的最后一种方法时。我仍然需要负值。 d1=np.ma.masked_array(c.copy(), c&lt;0)d2=np.ma.masked_array(c.copy(), c&gt;0) 。那么d=d1+d2。它不起作用。你能帮帮忙吗?
  • 我在最后加了一条注释
【解决方案2】:

np.sqrtufunc 并接受 where 参数。在这种情况下它可以用作掩码:

In [61]: c = np.arange(10)-5.0
In [62]: d = c.copy()
In [63]: np.sqrt(c, where=c>=0, out=d);
In [64]: d
Out[64]: 
array([-5.        , -4.        , -3.        , -2.        , -1.        ,
        0.        ,  1.        ,  1.41421356,  1.73205081,  2.        ])

np.where 的情况相比,这不会在 ~where 元素处计算函数。

【讨论】:

  • 这是我认为最干净的解决方案(也是最快的,至少在我的机器上)。
【解决方案3】:

这是您第二个问题的答案。

是的,您可以关闭警告。使用warnings 模块。

import warnings
warnings.filterwarnings("ignore")

【讨论】:

    【解决方案4】:

    一种解决方案是不使用np.where,而是使用索引。

    c = np.arange(10)-5
    d = c.copy()
    c_positive = c > 0
    d[c_positive] = np.sqrt(c[c_positive])
    

    【讨论】:

      猜你喜欢
      • 2014-06-13
      • 2018-01-29
      • 1970-01-01
      • 1970-01-01
      • 2010-10-03
      • 1970-01-01
      • 2011-04-03
      • 2014-07-06
      • 1970-01-01
      相关资源
      最近更新 更多