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.
Siehe auch