Numpy: Boolsche Indizierung

Boolean Maskes, as Venetian Mask
import numpy as np
A = np.array([4, 7, 3, 4, 2, 8])
print(A == 4)
[ True False False  True False False]

Jedes Element des Array A wird getestet, ob es gleich zu 4 ist. Die Ergebnisse der Prüfungen sind boolesche Elemente im Ergebnis-Array.

Natürlich kann die Prüfung auch mit "<", "<=", ">" und ">=" gemacht werden.

print(A < 5)
[ True False  True  True  True False]

Ebenfalls kann dies auf Arrays höherer Dimensionen angewendet werden:

B = np.array([[42,56,89,65],
              [99,88,42,12],
              [55,42,17,18]])
print(B>=42)
[[ True  True  True  True]
 [ True  True  True False]
 [ True  True False False]]

Es ist ein bequemer Weg um Schwellenwerte bei Bildern zu prüfen.

import numpy as np
A = np.array([
[12, 13, 14, 12, 16, 14, 11, 10,  9],
[11, 14, 12, 15, 15, 16, 10, 12, 11],
[10, 12, 12, 15, 14, 16, 10, 12, 12],
[ 9, 11, 16, 15, 14, 16, 15, 12, 10],
[12, 11, 16, 14, 10, 12, 16, 12, 13],
[10, 15, 16, 14, 14, 14, 16, 15, 12],
[13, 17, 14, 10, 14, 11, 14, 15, 10],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 17, 19, 16, 17, 18, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 16, 12, 14, 11, 12, 14, 18, 11],
[10, 19, 12, 14, 11, 12, 14, 18, 10],
[14, 22, 12, 14, 11, 12, 14, 17, 13],
[10, 16, 12, 14, 11, 12, 14, 18, 11]])
B = A < 15
B.astype(np.int)
Der obige Python-Code liefert folgendes Ergebnis:
array([[1, 1, 1, 1, 0, 1, 1, 1, 1],
       [1, 1, 1, 0, 0, 0, 1, 1, 1],
       [1, 1, 1, 0, 1, 0, 1, 1, 1],
       [1, 1, 0, 0, 1, 0, 0, 1, 1],
       [1, 1, 0, 1, 1, 1, 0, 1, 1],
       [1, 0, 0, 1, 1, 1, 0, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 0, 0, 0, 0, 0, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 1, 1, 1, 1, 1, 0, 1]])

Wenn Sie sich die Ausgabe genauer anschauen, so werden Sie sehen, dass die entsprechenden Werte aus A im Array nicht vorhanden sind.


Launische (Fancy) Indizierung

Wir indizieren im folgenden Beispiel ein Array C mit einer boolschen Maske. Man spricht von "launischer Indizierung" wenn Arrays mit boolschen oder Integer-Arrays (masks) für die Indizierung verwendet werden. Das Ergebnis ist dann eine Kopie und keine Sicht (View).

In unserem nächsten Beispiel benutzen wir die boolsche Maske eines Arrays um die entsprechenden Elemente eines anderen Arrays auszuwählen. Das neue Array R beinhaltet all die Elemente aus C, dessen entsprechenden Werte in A <= 5 sind.

C = np.array([123,188,190,99,77,88,100])
A = np.array([4,7,2,8,6,9,5])
R = C[A<=5]
print(R)
[123 190 100]


Indizierung mit einem Integer-Array

Im folgenden Beispiel indizieren wir mit Hilfe eines Integer-Arrays:

C[[0, 2, 3, 1, 4, 1]]
Wir erhalten die folgende Ergebnisse:
array([123, 190,  99, 188,  77, 188])

Indizes können in mehrfach und in beliebiger Reihenfolge auftreten!


Übung

Estrahieren Sie aus dem Array np.array([3,4,6,10,24,89,45,43,46,99,100]), anhand von boolscher Indizierung, die Werte, die:


Lösung

import numpy as np
A = np.array([3,4,6,10,24,89,45,43,46,99,100])
div3 = A[A%3!=0]
print("Elements of A not divisible by 3:")
print(div3)
div5 = A[A%5==0]
print("Elements of A divisible by 5:")
print(div5)
print("Elements of A, which are divisible by 3 and 5:")
print(A[(A%3==0) & (A%5==0)])
print("------------------")
# 
A[A%3==0] = 42
print("""New values of A after setting the elements of A, 
which are divisible by 3, to 42:""")
print(A)
Elements of A not divisible by 3:
[  4  10  89  43  46 100]
Elements of A divisible by 5:
[ 10  45 100]
Elements of A, which are divisible by 3 and 5:
[45]
------------------
New values of A after setting the elements of A, 
which are divisible by 3, to 42:
[ 42   4  42  10  42  89  42  43  46  42 100]


nonzero und where

Die Methode "nonzero" gibt es sowohl in ndarray und in numpy. Beide Funktionen sind äquivalent.

Für ein ndarry a liefern beide Varianten (numpy.nonzero(a) und a.nonzero() ) die Indizes der Elemente aus a die nicht 0 (non-zero) sind. Die Indizs werden als Tupel aus Arrays, eins für jede Dimension aus a, zurückgeliefert. Die entsprechenden non-zero-Werte können wie folgt gewonnen werden: tained with:

a[numpy.nonzero(a)]

import numpy as np
a = np.array([[0, 2, 3, 0, 1],
              [1, 0, 0, 7, 0],
              [5, 0, 0, 1, 0]])
print(a.nonzero())
(array([0, 0, 0, 1, 1, 2, 2]), array([1, 2, 4, 0, 3, 0, 3]))

Wenn Sie die Indizes nach Elementen gruppieren möchten, können Sie transpose benutzen:

transpose(nonzero(a))

Es wird ein zweidimensionales Array erzeugt. Jede Zeile entspricht einem non-zero-Element.

np.transpose(a.nonzero()) 
Der obige Code führt zu folgendem Ergebnis:
array([[0, 1],
       [0, 2],
       [0, 4],
       [1, 0],
       [1, 3],
       [2, 0],
       [2, 3]])

Die entsprechenden non-zero-Werte können wie folgt abgefragt werden:

 a[a.nonzero()]
Der obige Python-Code liefert Folgendes:
array([2, 3, 1, 1, 7, 5, 1])

Die Funktion "nonzero" kann dazu verwendet werde um die Indizes aus einem Array zu holen, bei denen die Bedingung True ist. Im folgenden Skript erstellen wir das boolsche Array B >= 42:

B = np.array([[42,56,89,65],
              [99,88,42,12],
              [55,42,17,18]])
print(B >= 42)
[[ True  True  True  True]
 [ True  True  True False]
 [ True  True False False]]

np.nonzero(B >= 42) produziert die Indizes aus B, auf die die Bedingung zutrifft.



Übung

Berechnen Sie die Primzahlen zwischen 0 und 100 mit Hilfe eines boolschen Arrays.



Lösung

import numpy as np
is_prime = np.ones((100,), dtype=bool)
# Cross out 0 and 1 which are not primes:
is_prime[:2] = 0
# cross out its higher multiples (sieve of Eratosthenes):
nmax = int(np.sqrt(len(is_prime)))
for i in range(2, nmax):
    is_prime[2*i::i] = False
print(np.nonzero(is_prime))
(array([ 2,  3,  5,  7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
       61, 67, 71, 73, 79, 83, 89, 97]),)



Flatnonzero und count_nonzero

ähnliche Funktionen: