【问题标题】:Numpy where function multiple conditionsNumpy where 函数多个条件
【发布时间】:2013-04-26 23:05:43
【问题描述】:

我有一个距离数组,称为 dists。我想选择两个值之间的分布。为此,我编写了以下代码行:

 dists[(np.where(dists >= r)) and (np.where(dists <= r + dr))]

但是这只选择条件

 (np.where(dists <= r + dr))

如果我使用临时变量按顺序执行命令,它可以正常工作。为什么上面的代码不起作用,我该如何让它起作用?

干杯

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    您的特定情况的最佳方法是将您的两个标准更改为一个标准:

    dists[abs(dists - r - dr/2.) <= dr/2.]
    

    它只创建一个布尔数组,在我看来更容易阅读,因为它说,drr 中是dist(虽然我会重新定义@ 987654326@ 成为您感兴趣区域的中心而不是开始,所以r = r + dr/2.)但这并不能回答您的问题。


    您的问题的答案:
    如果您只是想过滤掉不符合您条件的 dists 元素,您实际上并不需要 where

    dists[(dists >= r) & (dists <= r+dr)]
    

    因为&amp; 会给你一个元素and(括号是必要的)。

    或者,如果您出于某种原因确实想使用where,您可以这样做:

     dists[(np.where((dists >= r) & (dists <= r + dr)))]
    

    原因:
    它不起作用的原因是np.where 返回索引列表,而不是布尔数组。您试图在两个数字列表之间获取 and,这当然没有您期望的 True/False 值。如果ab 都是True 值,则a and b 返回b。所以说像[0,1,2] and [2,3,4] 这样的话只会给你[2,3,4]。它在行动中:

    In [230]: dists = np.arange(0,10,.5)
    In [231]: r = 5
    In [232]: dr = 1
    
    In [233]: np.where(dists >= r)
    Out[233]: (array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),)
    
    In [234]: np.where(dists <= r+dr)
    Out[234]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)
    
    In [235]: np.where(dists >= r) and np.where(dists <= r+dr)
    Out[235]: (array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12]),)
    

    您期望比较的只是布尔数组,例如

    In [236]: dists >= r
    Out[236]: 
    array([False, False, False, False, False, False, False, False, False,
           False,  True,  True,  True,  True,  True,  True,  True,  True,
            True,  True], dtype=bool)
    
    In [237]: dists <= r + dr
    Out[237]: 
    array([ True,  True,  True,  True,  True,  True,  True,  True,  True,
            True,  True,  True,  True, False, False, False, False, False,
           False, False], dtype=bool)
    
    In [238]: (dists >= r) & (dists <= r + dr)
    Out[238]: 
    array([False, False, False, False, False, False, False, False, False,
           False,  True,  True,  True, False, False, False, False, False,
           False, False], dtype=bool)
    

    现在您可以在组合布尔数组上调用np.where

    In [239]: np.where((dists >= r) & (dists <= r + dr))
    Out[239]: (array([10, 11, 12]),)
    
    In [240]: dists[np.where((dists >= r) & (dists <= r + dr))]
    Out[240]: array([ 5. ,  5.5,  6. ])
    

    或者简单地使用 fancy indexing 用布尔数组索引原始数组

    In [241]: dists[(dists >= r) & (dists <= r + dr)]
    Out[241]: array([ 5. ,  5.5,  6. ])
    

    【讨论】:

    • 这是一个非凡的答案。事实上,当您希望传递符合条件的索引时,您应该这样做。 where() 要求您再次过滤结果。
    【解决方案2】:

    接受的答案很好地解释了这个问题。然而,应用多个条件的更 Numpythonic 方法是使用numpy logical functions。在这种情况下,您可以使用np.logical_and

    np.where(np.logical_and(np.greater_equal(dists,r),np.greater_equal(dists,r + dr)))
    

    【讨论】:

    • 为什么logical_andcond1 &amp; cond2Numpythonic
    【解决方案3】:

    这里要指出一件有趣的事情;在这种情况下,通常使用 ORAND 的方法也可以使用,但需要稍作改动。而不是“and”而不是“or”,而是使用 Ampersand(&)Pipe Operator(|),它会起作用。

    当我们使用'and'时:

    ar = np.array([3,4,5,14,2,4,3,7])
    np.where((ar>3) and (ar<6), 'yo', ar)
    
    Output:
    ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
    

    当我们使用与号(&)时:

    ar = np.array([3,4,5,14,2,4,3,7])
    np.where((ar>3) & (ar<6), 'yo', ar)
    
    Output:
    array(['3', 'yo', 'yo', '14', '2', 'yo', '3', '7'], dtype='<U11')
    

    当我们尝试在 pandas Dataframe 中应用多个过滤器时,情况也是如此。现在,这背后的原因必须与逻辑运算符和位运算符有关,为了更多地了解它们,我建议在 stackoverflow 中查看answer 或类似的 Q/A。

    更新

    一位用户问,为什么需要在括号内给出 (ar>3) 和 (ar

    与 BODMAS 类似,python 也优先考虑应该首先执行的操作。括号内的项目首先执行,然后按位运算符开始工作。我将在下面展示当你使用和不使用“(”,“)”时两种情况下会发生什么。

    案例1:

    np.where( ar>3 & ar<6, 'yo', ar)
    np.where( np.array([3,4,5,14,2,4,3,7])>3 & np.array([3,4,5,14,2,4,3,7])<6, 'yo', ar)
    

    因为这里没有括号,所以位运算符(&amp;)在这里变得很困惑,你甚至要求它得到逻辑与,因为如果你看到,在运算符优先级表中,&amp; 给出优先于 &lt;&gt; 运算符。这是从最低优先级到最高优先级的表格。

    它甚至没有执行&lt;&gt; 操作并被要求执行逻辑与操作。所以这就是它给出错误的原因。

    可以查看以下链接以了解更多信息:operator precedence

    现在来看案例 2:

    如果你确实使用了括号,你会清楚地看到会发生什么。

    np.where( (ar>3) & (ar<6), 'yo', ar)
    np.where( (array([False,  True,  True,  True, False,  True, False,  True])) & (array([ True,  True,  True, False,  True,  True,  True, False])), 'yo', ar)
    

    True 和 False 的两个数组。您可以轻松地对它们执行逻辑与运算。这给了你:

    np.where( array([False,  True,  True, False, False,  True, False, False]),  'yo', ar)
    

    剩下的你知道,np.where,对于给定的情况,如果为 True,则分配第一个值(即此处为 'yo'),如果为 False,则分配另一个值(即此处,保留原始值)。

    就是这样。我希望我能很好地解释查询。

    【讨论】:

    • 为什么一定要在(ar&gt;3)(ar&gt;6)周围加上()
    • 这是一个非常好的问题。这是一个很好的问题,以至于我不得不自己思考到底需要它什么。所以我做到了,也问了一位同事,我们讨论了 amd 现在我确实为您提供了解决方案。将其作为更新放在答案中。这真的很简单,但真的很难理解。
    • 查看更新 RTrain3k,我已经回答了您的问题。
    【解决方案4】:

    我喜欢将np.vectorize 用于此类任务。考虑以下几点:

    >>> # function which returns True when constraints are satisfied.
    >>> func = lambda d: d >= r and d<= (r+dr) 
    >>>
    >>> # Apply constraints element-wise to the dists array.
    >>> result = np.vectorize(func)(dists) 
    >>>
    >>> result = np.where(result) # Get output.
    

    您也可以使用np.argwhere 代替np.where 以获得清晰的输出。

    【讨论】:

    • 这非常慢。正如文档已经指出的那样:“提供 vectorize 函数主要是为了方便,而不是为了性能。实现本质上是一个 for 循环。”
    【解决方案5】:

    试试:

    import numpy as np
    dist = np.array([1,2,3,4,5])
    r = 2
    dr = 3
    np.where(np.logical_and(dist> r, dist<=r+dr))
    

    输出:(array([2, 3, 4]),)

    您可以查看Logic functions了解更多详情。

    【讨论】:

      【解决方案6】:

      试试:

      np.intersect1d(np.where(dists >= r)[0],np.where(dists <= r + dr)[0])
      

      【讨论】:

        【解决方案7】:

        这应该可行:

        dists[((dists >= r) & (dists <= r+dr))]
        

        【讨论】:

          【解决方案8】:

          我已经制定了这个简单的例子

          import numpy as np
          
          ar = np.array([3,4,5,14,2,4,3,7])
          
          print [X for X in list(ar) if (X >= 3 and X <= 6)]
          
          >>> 
          [3, 4, 5, 4, 3]
          

          【讨论】:

          • 这种情况下不需要迭代。 NumPy 具有布尔索引。
          【解决方案9】:

          要让np.where() 处理多个条件,只需执行以下操作:

          np.where((condition 1) & (condition 2)) # for and
          np.where((condition 1) | (condition 2)) # for or
          

          我知道这重复了一些其他答案,但我把这个简单的答案放在这里,以供那些仍然想知道“为什么我会收到关于 The truth value of an array with more than one element is ambiguous 的烦人错误消息”的人们对正在解决的非常冗长和复杂的答案感到困惑原始帖子的专业性质。

          现在,至于 为什么 numpy 在您使用 and 而不是 &amp; 时会中断,我不会在这里尝试回答。它只是在此处看到其他答案以进行解释。恕我直言,他们似乎应该修复而不是强迫它保持一致性。或者至少他们应该发出一个特殊的错误信息。 :)

          【讨论】:

            猜你喜欢
            • 2021-04-08
            • 1970-01-01
            • 1970-01-01
            • 2018-12-20
            • 2012-05-19
            • 2022-01-19
            • 2015-06-16
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多