2011-08-24 31 views
8
中使用布爾索引掩模的多個級別

我有以下代碼首先選擇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 

這是不是很在這太問題列出了同樣的問題: Numpy array, how to select indices satisfying multiple conditions? - 因爲我使用的隨機數生成,我不希望有生成一個完整的面具,只針對所選的元素第一個面具。

回答

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修改該副本而不是原始數組。

+0

完美,正是我一直在尋找。 – Hemmer

+0

也有任何複製您發佈的代碼段中涉及的數組? – Hemmer

+1

@Hemmer:有'np.where'和'[second_mask]'創建了新的數組。這些數組的大小取決於'mask'和'second_mask'中True元素的數量,並且與'grid'的大小無關。 – NPE

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 

雖然這是一個有點長,好像讀更好的(我的眼睛初學者),並在速度測試它執行的同時。

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()返回一個平面視圖爲原始陣列。

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