【问题标题】:python numpy where returning unexpected warningpython numpy在哪里返回意外警告
【发布时间】:2018-04-10 17:52:21
【问题描述】:

使用python 2.7,scipy 1.0.0-3

显然我对 numpy where 函数应该如何运行或在其运行中存在已知错误存在误解。我希望有人能告诉我哪个并解释一种解决方法来抑制我试图避免的烦人的警告。当我使用 pandas Series where() 时,我得到了相同的行为。

为了简单起见,我将使用一个 numpy 数组作为示例。假设我想在数组上应用 np.log(),并且只有在条件下,值才是有效输入,即 myArray>0.0。对于不应应用此函数的值,我想将输出标志设置为 -999.9:

myArray = np.array([1.0, 0.75, 0.5, 0.25, 0.0])
np.where(myArray>0.0, np.log(myArray), -999.9)

我希望 numpy.where() 不会抱怨数组中的 0.0 值,因为那里的条件是 False,但它确实如此,而且它似乎实际上是针对该 False 条件执行的:

-c:2: RuntimeWarning: divide by zero encountered in log 
array([  0.00000000e+00,  -2.87682072e-01,  -6.93147181e-01,
        -1.38629436e+00,  -9.99900000e+02])

numpy documentation 声明:

如果给定 x 和 y 并且输入数组是一维数组,则等效于: [xv if c else yv for (c,xv,yv) in zip(condition,x,y)]

我不同意这种说法,因为

[np.log(val) if val>0.0 else -999.9 for val in myArray]

根本不提供警告:

[0.0, -0.2876820724517809, -0.69314718055994529, -1.3862943611198906, -999.9] 

那么,这是一个已知的错误吗?我不想抑制整个代码的警告。

【问题讨论】:

    标签: python pandas numpy


    【解决方案1】:

    您可以仅使用可选的where 参数在相关位置评估log

    np.where(myArray>0.0, np.log(myArray, where=myArray>0.0), -999.9)
    

    或者更高效

    mask = myArray > 0.0
    np.where(mask, np.log(myArray, where=mask), -999)
    

    或者如果你发现“双重位置”丑陋

    np.log(myArray, where=myArray>0.0, out=np.full(myArray.shape, -999.9))
    

    这三个中的任何一个都应该抑制警告。

    【讨论】:

      【解决方案2】:

      如果对 Python 有基本的了解,where 的这种行为应该是可以理解的。这是一个 Python 表达式,它使用了几个 numpy 函数。

      这个表达式会发生什么?

      np.where(myArray>0.0, np.log(myArray), -999.9)
      

      解释器首先评估函数的所有参数,然后将结果传递给where。那么有效:

      cond = myArray>0.0
      A = np.log(myArray)
      B = -999.9
      np.where(cond, A, B)
      

      警告是在第 2 行而不是第 4 行产生的。

      第4行相当于:

      [xv if c else yv for (c,xv,yv) in zip(cond, A, B)]
      

      [A[i] if c else B for i,c in enumerate(cond)]
      

      np.where 最常与一个参数一起使用,它是np.nonzero 的同义词。我们在 SO 上看不到这种三参数形式。它没那么有用,部分原因是它不会节省计算量。

      蒙面分配更为常见,尤其是在有超过 2 个备选方案的情况下。

      In [123]: mask = myArray>0
      In [124]: out = np.full(myArray.shape, np.nan)
      In [125]: out[mask] = np.log(myArray[mask])
      In [126]: out
      Out[126]: array([ 0.        , -0.28768207, -0.69314718, -1.38629436,         nan])
      

      Paul Panzer 展示了如何使用 logwhere 参数执行相同的操作。该功能没有被尽可能多地使用。

      In [127]: np.log(myArray, where=mask, out=out)
      Out[127]: array([ 0.        , -0.28768207, -0.69314718, -1.38629436,         nan])
      

      【讨论】:

        【解决方案3】:

        这不是错误。有关类似问题,请参阅 this related answer。文档中的示例具有误导性,但该答案对其进行了详细说明。

        问题在于,三元语句在编译时由解释器处理,而numpy.where常规函数。因此,三元语句允许短路,而在事先定义参数时这是不可能的。

        换句话说,numpy.where 的参数是在处理布尔数组之前计算的。

        您可能会认为这是低效的:为什么要构建 2 个单独的数组,然后使用第 3 个布尔数组来决定选择哪个项目?肯定是双倍的工作/双倍的内存?

        但是,这种低效率被numpy 作用于整个数组的函数提供的向量化所抵消,例如np.log(arr).


        考虑文档中提供的示例:

        如果给定xy 并且输入数组 是一维的,则where 是 相当于::

            [xv if c else yv for (c,xv,yv) in zip(condition,x,y)]
        

        注意输入是数组。尝试运行:

        c = np.array([0])
        
        result = [xv if c else yv for (c, xv, yv) in zip(c==0, np.array([1]), np.log(c))]
        

        你会注意到这个错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-12-21
          • 1970-01-01
          • 2011-09-17
          • 2016-01-19
          • 2021-09-21
          • 1970-01-01
          相关资源
          最近更新 更多