Использование нескольких уровней маски логического индекса в NumPy - PullRequest
8 голосов
/ 24 августа 2011

У меня есть следующий код, который сначала выбирает элементы массива 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, как выбрать индексы, удовлетворяющие нескольким условиям? - поскольку я использую генерацию случайных чисел, я нене нужно создавать полную маску, только для элементов, выбранных первой маской.

Ответы [ 4 ]

6 голосов
/ 24 августа 2011

Я полагаю, что следующее делает то, что вы просите:

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

Работает следующим образом:

  • np.where(mask) преобразует логическую маску в индексы, где mask - Истина;
  • [a[second_mask] for a in ...] подмножества индексов, чтобы выбрать только те, где second_mask Истина.

Причина, по которой ваша оригинальная версия не работает, заключается в том, что grid[mask] включает в себя необычную индексацию. Это создает копию данных, что, в свою очередь, приводит к ...[second_mask] = 100 изменению этой копии, а не к исходному массиву.

2 голосов
/ 11 июня 2013

Использование плоской индексации позволяет избежать головной боли:

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 и присваивает 100.grid.ravel()[ind] = 100 также будет работать, так как ravel() возвращает плоский вид в исходный массив.

0 голосов
/ 29 марта 2014
In [29]: ar = linspace(1,10,10)
In [30]: ar[(3<ar)*(ar<8)]
Out[30]: array([ 4.,  5.,  6.,  7.])
0 голосов
/ 25 августа 2011

Другое возможное решение, которое я придумал, подумав об этом немного больше, - это чтобы вторая карта сохранила размер первой (которая может или не может стоить попадания в память) и выборочно добавила новые элементы:

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

Хотя это немного дольше, кажется, что он читается лучше (на мой взгляд начинающим), и в тестах скорости он выполняет в то же время.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...