【问题标题】:Using multiple levels of boolean index mask in NumPy在 NumPy 中使用多级布尔索引掩码
【发布时间】:2011-11-03 00:27:01
【问题描述】:

我有以下代码,它首先选择具有逻辑索引掩码的 NumPy 数组的元素:

import numpy as np

grid = np.random.rand(4,4) 
mask = grid > 0.5

我希望对这个使用第二个布尔掩码来挑选对象:

masklength = len(grid[mask])
prob = 0.5
# generates an random array of bools
second_mask = np.random.rand(masklength) < prob 

# this fails to act on original object
grid[mask][second_mask] = 100

这与此 SO 问题中列出的问题并不完全相同: Numpy array, how to select indices satisfying multiple conditions? - 因为我使用的是随机数生成,所以我不想生成一个完整的掩码,只针对第一个掩码选择的元素。

【问题讨论】:

    标签: python numpy


    【解决方案1】:

    使用平面索引可以避免很多麻烦:

    grid.flat[np.flatnonzero(mask)[second_mask]] = 100
    

    分解:

    ind = np.flatnonzero(mask)
    

    mask 为真时生成一个平面索引数组,然后通过应用second_mask 进一步抽取:

    ind = ind[second_mask] 
    

    我们可以继续:

    ind = ind[third_mask]
    

    终于

    grid.flat[ind] = 100
    

    ind 索引grid 的平面版本并分配100grid.ravel()[ind] = 100 也可以工作,因为 ravel() 将平面视图返回到原始数组中。

    【讨论】:

      【解决方案2】:

      我相信以下内容可以满足您的要求:

      grid[[a[second_mask] for a in np.where(mask)]] = 100
      

      它的工作原理如下:

      • np.where(mask) 将布尔掩码转换为 mask 为 True 的索引;
      • [a[second_mask] for a in ...] 对索引进行子集化,以仅选择 second_mask 为 True 的索引。

      您的原始版本不起作用的原因是grid[mask] 涉及花哨的索引。这会创建数据的副本,进而导致...[second_mask] = 100 修改该副本而不是原始数组。

      【讨论】:

      • 完美,正是我想要的。
      • 还有你贴的sn-p中涉及到的数组复制吗?
      • @Hemmer:np.wherea[second_mask] 创建了新数组。这些数组的大小取决于 masksecond_mask 中 True 元素的数量,并且与 grid 的大小无关。
      • 我已经发布了一个替代解决方案,如果您有兴趣,我会找到它。
      • 只需通过grid[mask &amp; second_mask]组合掩码。
      【解决方案3】:

      另一个可能的解决方案是我在考虑更多之后想出的让第二个地图保留第一个地图的大小(这可能值得也可能不值得内存命中)并有选择地添加新元素:

      #!/usr/bin/env python
      import numpy as np
      
      prob = 0.5    
      grid = np.random.rand(4,4)
      
      mask = grid > 0.5 
      masklength = np.sum(mask)
      
      # initialise with false map
      second_mask = np.zeros((4,4), dtype=np.bool)
      # then selectively add to this map using the second criteria
      second_mask[mask] = np.random.rand(masklength) < prob
      
      # this now acts on the original object
      grid[second_mask] = 100
      

      虽然这有点长,但它似乎读起来更好(在我的初学者眼中),并且在速度测试中它同时执行。

      【讨论】:

        【解决方案4】:
        In [29]: ar = linspace(1,10,10)
        In [30]: ar[(3<ar)*(ar<8)]
        Out[30]: array([ 4.,  5.,  6.,  7.])
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-11-04
          • 1970-01-01
          • 2019-10-29
          • 2016-02-16
          • 2020-02-14
          • 1970-01-01
          • 1970-01-01
          • 2020-03-25
          相关资源
          最近更新 更多