Indizierung und Slicing

Indizierung ist die Auswahl einer Teilmenge eurer Daten oder einzelner Elemente. In eindimensionalen Arrays ist das sehr einfach; verhalten sie sich doch ähnlich wie Python-Listen:

[1]:
import numpy as np
[2]:
data = np.random.randn(7, 3)
data
[2]:
array([[ 0.33050115, -0.24519424,  0.66232884],
       [ 0.22530574,  0.41200361,  1.21487789],
       [ 0.20448321,  0.91945497,  1.51575382],
       [ 1.28360113, -0.14962714,  0.22448488],
       [ 0.04452226,  0.88346213,  1.75586787],
       [-0.48891048, -1.73687276, -2.47068694],
       [ 0.96051183,  2.09280516,  0.28880627]])
[3]:
data[4]
[3]:
array([0.04452226, 0.88346213, 1.75586787])
[4]:
data[2:4]
[4]:
array([[ 0.20448321,  0.91945497,  1.51575382],
       [ 1.28360113, -0.14962714,  0.22448488]])
[5]:
data[2:4] = np.random.randn(2, 3)
[6]:
data
[6]:
array([[ 0.33050115, -0.24519424,  0.66232884],
       [ 0.22530574,  0.41200361,  1.21487789],
       [ 1.46155705, -1.42462688, -0.64299548],
       [ 0.37948229,  1.29346366, -0.84481165],
       [ 0.04452226,  0.88346213,  1.75586787],
       [-0.48891048, -1.73687276, -2.47068694],
       [ 0.96051183,  2.09280516,  0.28880627]])

Bemerkung

Array-Slices unterscheiden sich von Python-Listen dadurch, dass sie Sichten (views) auf das ursprüngliche Array sind. Das bedeutet, dass die Daten nicht kopiert werden und dass alle Änderungen an der View im Ausgangsarray wiedergegeben werden.

Wenn ihr eine Kopie eines Teils eines ndarray erstellen wollt, könnt ihr das Array explizit kopieren – z.B. mit data[2:5].copy().

Slicing in dieser Weise führt immer zu Array-Ansichten mit der gleichen Anzahl von Dimensionen. Wenn ihr jedoch ganzzahlige Indizes und Slices mischt, erhaltet ihr Slices mit niedrigeren Dimensionen. So können wir z.B. die zweite Zeile, aber nur die ersten beiden Spalten wie folgt auswählen:

[7]:
data[1, :2]
[7]:
array([0.22530574, 0.41200361])

Ein Doppelpunkt bedeutet, dass die gesamte Achse genommen wird, so dass ihr auch höherdimensionale Achsen auswählen könnt:

[8]:
data[:, :1]
[8]:
array([[ 0.33050115],
       [ 0.22530574],
       [ 1.46155705],
       [ 0.37948229],
       [ 0.04452226],
       [-0.48891048],
       [ 0.96051183]])

Boolesche Indizierung

Betrachten wir ein Beispiel, bei dem wir einige Daten in einem Array und ein Array von Namen mit Duplikaten haben. Ich werde hier die Funktion randn in numpy.random verwenden, um einige zufällige normalverteilte Daten zu erzeugen:

[9]:
names = np.array(
    [
        "Liam",
        "Olivia",
        "Noah",
        "Liam",
        "Noah",
        "Olivia",
        "Liam",
        "Emma",
        "Oliver",
        "Ava",
    ]
)
data = np.random.randn(10, 4)
[10]:
names
[10]:
array(['Liam', 'Olivia', 'Noah', 'Liam', 'Noah', 'Olivia', 'Liam', 'Emma',
       'Oliver', 'Ava'], dtype='<U6')
[11]:
data
[11]:
array([[-0.1353117 ,  0.81134636,  1.27451527,  1.05352755],
       [-1.13514458,  0.54537619,  1.82156905, -1.01267531],
       [ 1.09013813,  0.87177598, -0.62723958,  0.40875051],
       [ 0.2705055 , -1.95543273,  1.69239456, -1.63625339],
       [ 0.51631929,  1.05609607,  0.83749348,  0.03833032],
       [-1.15009072, -0.24253528, -0.63441305,  0.05945932],
       [-0.02354212,  0.97168249,  0.81879396, -1.45633432],
       [-0.0938235 , -0.76430898,  1.58021321,  0.84109544],
       [-1.06054123, -0.29494841, -1.71638201,  1.25419797],
       [ 1.04045002,  1.04053515, -1.26912014,  1.04517256]])

Angenommen, jeder Name entspricht einer Zeile im Datenarray und wir wollen alle Zeilen mit dem entsprechenden Namen Liam auswählen. Wie arithmetische Operationen werden auch Vergleiche wie == mit Arrays vektorisiert. Der Vergleich von Namen mit der Zeichenkette Liam ergibt also ein boolesches Array:

[12]:
names == "Liam"
[12]:
array([ True, False, False,  True, False, False,  True, False, False,
       False])

Dieses boolesche Array kann beim Indizieren des Arrays übergeben werden:

[13]:
data[names == "Liam"]
[13]:
array([[-0.1353117 ,  0.81134636,  1.27451527,  1.05352755],
       [ 0.2705055 , -1.95543273,  1.69239456, -1.63625339],
       [-0.02354212,  0.97168249,  0.81879396, -1.45633432]])

Dabei muss das boolesche Array die gleiche Länge haben wie die Arrayachse, die es indiziert.

Bemerkung

Die Auswahl von Daten aus einem Array durch boolesche Indizierung und die Zuweisung des Ergebnisses an eine neue Variable erzeugt immer eine Kopie der Daten, selbst wenn das zurückgegebene Array unverändert ist.

Im folgenden Beispiel wähle ich die Zeilen aus, in denen Namen == "Liam" ist und indiziere auch die Spalten:

[14]:
data[names == "Liam", 2:]
[14]:
array([[ 1.27451527,  1.05352755],
       [ 1.69239456, -1.63625339],
       [ 0.81879396, -1.45633432]])

Um alles außer Liam auszuwählen, könnt ihr entweder != verwenden oder die Bedingung mit ~ negieren:

[15]:
names != "Liam"
[15]:
array([False,  True,  True, False,  True,  True, False,  True,  True,
        True])
[16]:
cond = names == "Liam"
data[~cond]
[16]:
array([[-1.13514458,  0.54537619,  1.82156905, -1.01267531],
       [ 1.09013813,  0.87177598, -0.62723958,  0.40875051],
       [ 0.51631929,  1.05609607,  0.83749348,  0.03833032],
       [-1.15009072, -0.24253528, -0.63441305,  0.05945932],
       [-0.0938235 , -0.76430898,  1.58021321,  0.84109544],
       [-1.06054123, -0.29494841, -1.71638201,  1.25419797],
       [ 1.04045002,  1.04053515, -1.26912014,  1.04517256]])

Wenn ihr zwei der drei Namen auswählt, um mehrere boolesche Bedingungen zu kombinieren, könnt ihr die booleschen arithmetischen Operatoren & (und) und | (oder) verwenden.

Warnung

Die Python-Schlüsselwörter and und or funktionieren nicht mit booleschen Arrays.

[17]:
mask = (names == "Liam") | (names == "Olivia")
[18]:
mask
[18]:
array([ True,  True, False,  True, False,  True,  True, False, False,
       False])
[19]:
data[mask]
[19]:
array([[-0.1353117 ,  0.81134636,  1.27451527,  1.05352755],
       [-1.13514458,  0.54537619,  1.82156905, -1.01267531],
       [ 0.2705055 , -1.95543273,  1.69239456, -1.63625339],
       [-1.15009072, -0.24253528, -0.63441305,  0.05945932],
       [-0.02354212,  0.97168249,  0.81879396, -1.45633432]])

Ganzzahlige Array-Indizierung

Ganzzahlige Array-Indizierung ermöglicht die Auswahl beliebiger Elemente im Array auf der Grundlage eures N-dimensionalen Index. Jedes Integer-Array repräsentiert eine Anzahl von Indizes in dieser Dimension.