在NumPy中使用多级布尔索引掩码

时间:2011-08-24 17:12:45

标签: python numpy

我有以下代码首先选择具有逻辑索引掩码的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? - 因为我使用随机数生成,我不想生成完整的掩码,仅用于第一个掩码选择的元素。

4 个答案:

答案 0 :(得分:6)

我相信以下内容符合您的要求:

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修改该副本而不是原始数组。

答案 1 :(得分:2)

使用平面索引避免了大部分问题:

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

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

答案 2 :(得分:0)

在考虑了这个之后我想出的另一个可能的解决方案是让第二个映射保留第一个映射的大小(可能或可能不值得记忆命中)并选择性地添加新元素:

#!/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

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

答案 3 :(得分:0)

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