2011-08-24 12 views
8

I mają następujące oznaczenia, które wybiera najpierw elementy tablicy NumPy z logicznym maski index:Użycie wielu poziomów logicznych na masce indeksu w NumPy

import numpy as np 

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

życzę użycie drugiego logiczną maski na tym jednym do wybierać obiekty z:

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 

to nie jest całkiem taki sam problem jak wymienione w tym SO pytanie: Numpy array, how to select indices satisfying multiple conditions? - jak używam generowania liczb losowych, nie chcę mieć do generowania pełną maskę, tylko dla elementów wybranych przez pierwsza maska.

Odpowiedz

6

wierzę dodaje robi co pytasz:

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

To działa w następujący sposób:

  • np.where(mask) konwertuje logiczną maskę do indeksów gdzie mask jest prawdą;
  • [a[second_mask] for a in ...] podzestaw indeksy tak, aby wybierać tylko te, w których second_mask ma wartość True.

Powodem, dla którego oryginalna wersja nie działa, jest to, że grid[mask] zawiera wymyślne indeksowanie. Spowoduje to utworzenie kopii danych, co z kolei spowoduje zmianę tej kopii, a nie oryginalnej tablicy.

+0

Idealne, właśnie to, czego szukałem. – Hemmer

+0

Czy w opublikowanym fragmencie jest również jakieś kopiowanie tablic? – Hemmer

+1

@Hemmer: Są nowe tablice utworzone przez 'np.where' i' a [second_mask] '. Rozmiar tych tablic zależy od liczby elementów True w maskach i maskach second_ i jest niezależny od wielkości 'grid'. – NPE

0

Innym możliwym rozwiązaniem, które wymyśliłem po przemyśleniu tego, jest to, że druga mapa zachowuje wielkość pierwszego (która może lub nie jest warta pamięci) i selektywnie dodaje nowe elementy :

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

Choć jest to nieco dłużej, wydaje się, że lepiej przeczytać (na moich oczach początkujących) oraz w testach prędkości wykonuje ono w tym samym czasie.

2

stosując płaskie indeksowania eliminuje wiele bólu głowy:

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

jego rozbijania:

ind = np.flatnonzero(mask) 

tworzy płaską tablicę wskaźników, gdzie mask prawda, który następnie decymacji dalej stosując second_mask :

ind = ind[second_mask] 

Możemy przejść dalej:

ind = ind[third_mask] 

Wreszcie

grid.flat[ind] = 100 

indeksy płaską wersją grid z ind i przypisuje 100. grid.ravel()[ind] = 100 również będzie działać, ponieważ ravel() zwraca płaski widok do oryginalnej tablicy.

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