Indexierung und Slicing
Indexing wählt Werte an bestimmten Positionen aus, Slicing dagegen einen Bereich entlang einer oder mehrerer Achsen. Ein Slice einer Python-Liste erzeugt eine neue Liste. Basic Slicing eines ndarray liefert eine View mit gemeinsam genutzten Daten. Das Lesen durch Advanced Indexing mit Integer- oder Boolean-Arrays erzeugt dagegen eine Kopie.
Eine View vermeidet das Kopieren der Daten. Schreibst du jedoch über die View, ändern sich auch die entsprechenden Werte im ursprünglichen Array.
Eindimensionale Operationen mit Arrays
Eindimensionale Arrays verwenden die vertraute Indexing-Syntax von Python. Ein Basic Slice wie a[1:4] liefert eine View. Änderungen an dieser View betreffen daher dieselben Elemente in a.
import numpy as np
# Ein 1D-Array erstellen
a = np.linspace(0, 7, 8)
print("Ursprüngliches Array:", a) # Ausgabe: Ursprüngliches Array: [0. 1. 2. 3. 4. 5. 6. 7.]
# Indizierung einzelner Elemente
print("Element am Index 3:", a[3]) # Ausgabe: Element am Index 3: 3.0
print("Letztes Element:", a[-1]) # Ausgabe: Letztes Element: 7.0
# Grundlegendes Slicing
print("Slice [2:6]:", a[2:6]) # Ausgabe: Slice [2:6]: [2. 3. 4. 5.]
print("Slice [3:-2]:", a[3:-2]) # Ausgabe: Slice [3:-2]: [3. 4. 5.]
# Modifikation durch Slicing (ändert das ursprüngliche Array)
a[:3] = 0
print("Nach a[:3] = 0:", a) # Ausgabe: Nach a[:3] = 0: [0. 0. 0. 3. 4. 5. 6. 7.]Das nächste Beispiel verändert eine View und eine Kopie getrennt. Die View teilt den Speicher mit dem ursprünglichen Array, während .copy() unabhängige Daten anlegt.
import numpy as np
# Ursprüngliches Array
original = np.array([1, 2, 3, 4, 5])
print("Original:", original) # Ausgabe: Original: [1 2 3 4 5]
# Ansicht durch Slicing erstellen
view = original[1:4]
print("View:", view) # Ausgabe: View: [2 3 4]
# Ansicht ändern (betrifft Original)
view[0] = 999
print("Nach dem Ändern der Ansicht:")
print("Original:", original) # Ausgabe: Original: [ 1 999 3 4 5]
print("View:", view) # Ausgabe: View: [999 3 4]
# Eine unabhängige Kopie anlegen
copy_array = original[1:4].copy()
copy_array[0] = 777
print("Nach dem Ändern der Kopie:")
print("Original:", original) # Ausgabe: Original: [ 1 999 3 4 5]
print("Kopie:", copy_array) # Ausgabe: Kopie: [777 3 4]Multidimensionale Operationen mit Arrays
In einer mehrdimensionalen Auswahl spricht jeder durch Komma getrennte Eintrag eine Dimension des Arrays an, beginnend mit der ersten Dimension. Ein ganzzahliger Index entfernt diese Dimension aus dem Ergebnisarray, ein Schnitt wie : behält sie bei. Zum Beispiel liefert a[1, :] für das zweidimensionale Array a ein eindimensionales Array mit der zweiten Zeile, während a[1:2, :] weiterhin ein zweidimensionales Array mit einer Zeile liefert.
import numpy as np
# Ein 2D-Array erstellen
a = np.array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.],
[10., 11., 12.]])
print("2D-Array:")
print(a)
# Ausgabe:
# [[ 1. 2. 3.]
# [ 4. 5. 6.]
# [ 7. 8. 9.]
# [10. 11. 12.]]
# Spezifische Elementindizierung
print("a[2,1]:", a[2,1]) # Ausgabe: a[2,1]: 8.0
# Eine Zeile auswählen
print("a[1,:]:", a[1,:]) # Ausgabe: a[1,:]: [4. 5. 6.]
# Eine Spalte auswählen
print("a[:,2]:", a[:,2]) # Ausgabe: a[:,2]: [ 3. 6. 9. 12.]Kombinierte Slices auf mehreren Achsen wählen rechteckige oder schrittweise Teilarrays aus, ohne dass du eine Schleife schreiben musst:
import numpy as np
# 2D-Array zur Demonstration
a = np.array([[1., 2., 3.],
[4., 5., 6.],
[7., 8., 9.],
[10., 11., 12.]])
# Subarray-Slicing
print("a[1:3, 0:2]:")
print(a[1:3, 0:2])
# Ausgabe:
# [[4. 5.]
# [7. 8.]]
# Slicing mit Schrittweite
print("a[::2, :]:")
print(a[::2, :])
# Ausgabe:
# [[1. 2. 3.]
# [7. 8. 9.]]
# Spaltenschneiden mit Schritt
print("a[:, ::2]:")
print(a[:, ::2])
# Ausgabe:
# [[ 1. 3.]
# [ 4. 6.]
# [ 7. 9.]
# [10. 12.]]Zweidimensionale Operationen im Überblick
Die Tabelle sammelt die Index- und Slice-Formen für ein zweidimensionales Array an einer Stelle, zusammen mit der Form jedes Ergebnisses.
| Operation | Beschreibung | Beispielergebnis |
|---|---|---|
a[2,1] | Element in Zeile , Spalte | Einzelwert: 8.0 |
a[1,:] | Ganze Zeile | Eindimensionales Array: [4. 5. 6.] |
a[:,2] | Gesamte Spalte | Eindimensionales Array: [3. 6. 9. 12.] |
a[1:3, 0:2] | Subarray Zeilen , Spalten | Zweidimensionales Array: [[4. 5.], [7. 8.]] |
a[::2, :] | Jede zweite Zeile | Zweidimensionales Array mit Zeilen |
a[:, ::2] | Jede zweite Spalte | Zweidimensionales Array mit Spalten |
Erweiterte Indizierung
Advanced Indexing wählt mit Integer- oder Boolean-Arrays beliebige Elemente aus und liefert immer eine Kopie. Bei einer eindimensionalen Quelle bestimmt das Indexarray die Form des Ergebnisses. Bei mehrdimensionalen Quellen broadcastet NumPy die Indexarrays und kombiniert ihre Form mit den Dimensionen, die durch Basic Slices übrig bleiben.
import numpy as np
# Array zur Demonstration
a = np.array([0, 1, 2, 3, 4])
print("Ursprüngliches Array:", a) # Ausgabe: Ursprüngliches Array: [0 1 2 3 4]
# Indizierung mit Indexliste
i = [1, 3, 2, 1, 4]
print("Indexarray:", i) # Ausgabe: Indexarray: [1, 3, 2, 1, 4]
print("a[i]:", a[i]) # Ausgabe: a[i]: [1 3 2 1 4]
# Indizieren und Umformen mit 2D-Index-Array
i = np.array([[1, 2], [3, 4]])
print("2D-Indexarray:")
print(i)
# Ausgabe:
# [[1 2]
# [3 4]]
print("a[i]:")
print(a[i])
# Ausgabe:
# [[1 2]
# [3 4]]Eine boolesche Maske wählt die Positionen aus, deren Maskenwert True ist. Hat die Maske dieselbe Form wie das Quellarray, kommen die gewählten Werte als eindimensionale Kopie zurück.
import numpy as np
# Array zur Demonstration
a = np.linspace(0, 5, 6)
print("Array:", a) # Ausgabe: Array: [0. 1. 2. 3. 4. 5.]
# Eine boolesche Maske erstellen
mask = np.array([True, False, True, False, True, False])
print("Boolesche Maske:", mask) # Ausgabe: Boolesche Maske: [ True False True False True False]
print("a[mask]:", a[mask]) # Ausgabe: a[mask]: [0. 2. 4.]
# Boolesche Maske aus Bedingung
condition_mask = a % 2 == 0
print("Bedingungsmaske (a % 2 == 0):", condition_mask) # Ausgabe: Bedingungsmaske (a % 2 == 0): [ True False True False True False]
print("a[condition_mask]:", a[condition_mask]) # Ausgabe: a[condition_mask]: [0. 2. 4.]
# Boolesche Maske mit komplexen Bedingungen
complex_mask = (a > 1) & (a < 4)
print("Kombinierte Maske (a > 1) & (a < 4):", complex_mask) # Ausgabe: Kombinierte Maske (a > 1) & (a < 4): [False False True True False False]
print("a[complex_mask]:", a[complex_mask]) # Ausgabe: a[complex_mask]: [2. 3.]Advanced Indexes und Basic Slices können in derselben Auswahl stehen. Der fortgeschrittene Anteil sorgt weiterhin dafür, dass das Ergebnis eine Kopie ist:
import numpy as np
# 2D-Array zur Demonstration
a = np.arange(24).reshape(4, 6)
print("2D-Array:")
print(a)
# Ausgabe:
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
# Kombination aus Slicing und Indizierung
print("a[1:3, [0, 2, 5]]:")
print(a[1:3, [0, 2, 5]])
# Ausgabe:
# [[ 6 8 11]
# [12 14 17]]
# Boolesche Indizierung für Zeilen, Slicing für Spalten
row_mask = np.array([True, False, True, False])
print("a[row_mask, 2:5]:")
print(a[row_mask, 2:5])
# Ausgabe:
# [[ 2 3 4]
# [14 15 16]]Fortgeschrittene Techniken
Das dritte Feld eines Slice ist die Schrittweite. Damit wählst du regelmäßige Abstände aus, durchläufst mit negativen Werten eine Achse rückwärts und legst den Schritt für jede Achse getrennt fest.
import numpy as np
# Array zur Demonstration
a = np.arange(20)
print("Array:", a) # Ausgabe: Array: [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
# Slicing mit Schrittweite
print("a[::2] (jedes zweite Element):", a[::2]) # Ausgabe: a[::2] (jedes zweite Element): [ 0 2 4 6 8 10 12 14 16 18]
print("a[1::3] (ab Index 1 jedes dritte Element):", a[1::3]) # Ausgabe: a[1::3] (ab Index 1 jedes dritte Element): [ 1 4 7 10 13 16 19]
print("a[::-1] (umgekehrtes Array):", a[::-1]) # Ausgabe: a[::-1] (umgekehrtes Array): [19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0]
# Schrittweises Slicing im 2D-Array
b = np.arange(12).reshape(3, 4)
print("2D-Array:")
print(b)
# Ausgabe:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print("b[::2, ::2] (jede zweite Zeile und Spalte):")
print(b[::2, ::2])
# Ausgabe:
# [[ 0 2]
# [ 8 10]]Eine Ellipsis (...) ergänzt so viele vollständige Slices wie für die nicht angegebenen Dimensionen nötig sind. Dadurch bleiben Auswahlen in hochdimensionalen Arrays lesbar.
import numpy as np
# 3D-Array zur Demonstration
a = np.arange(24).reshape(2, 3, 4)
print("3D-Array-Form:", a.shape) # Ausgabe: 3D-Array-Form: (2, 3, 4)
# Ellipsis verwenden
print("a[0, ...] (dasselbe wie a[0, :, :]):")
print(a[0, ...])
# Ausgabe:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
print("a[..., 2] (dasselbe wie a[:, :, 2]):")
print(a[..., 2])
# Ausgabe:
# [[ 2 6 10]
# [14 18 22]]
print("a[1, ..., ::2] (dasselbe wie a[1, :, ::2]):")
print(a[1, ..., ::2])
# Ausgabe:
# [[12 14]
# [16 18]
# [20 22]]Boolesche Indizierung
Bei der booleschen Indizierung filtert ein boolesches Array die Elemente nach einer Bedingung. Ein True übernimmt das entsprechende Element, ein False lässt es aus.
import numpy as np
# Array zur Demonstration
a = np.linspace(0, 5, 6)
print("Array:", a) # Ausgabe: Array: [0. 1. 2. 3. 4. 5.]
# Manuelle boolesche Maske
mask = np.array([True, False, True, False, True, False], dtype=bool)
print("Manuelle Maske:", mask) # Ausgabe: Manuelle Maske: [ True False True False True False]
print("a[mask]:", a[mask]) # Ausgabe: a[mask]: [0. 2. 4.]
# Boolesche Maske aus dem Vergleich
greater_than_2 = a > 2
print("a > 2:", greater_than_2) # Ausgabe: a > 2: [False False False True True True]
print("a[a > 2]:", a[a > 2]) # Ausgabe: a[a > 2]: [3. 4. 5.]
# Boolesche Maske mit zusammengesetzten Bedingungen
even_and_greater_than_1 = (a % 2 == 0) & (a > 1)
print("(a % 2 == 0) & (a > 1):", even_and_greater_than_1) # Ausgabe: (a % 2 == 0) & (a > 1): [False False True False True False]
print("a[even_and_greater_than_1]:", a[even_and_greater_than_1]) # Ausgabe: a[even_and_greater_than_1]: [2. 4.]Eine gleich geformte boolesche Maske wählt passende Elemente aus einem zweidimensionalen Array aus und gibt sie eindimensional zurück:
import numpy as np
# 2D-Array zur Demonstration
a = np.arange(12).reshape(3, 4)
print("2D-Array:")
print(a)
# Ausgabe:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# Boolesche Maske für bestimmte Elemente
mask = a > 5
print("Maske a > 5:")
print(mask)
# Ausgabe:
# [[False False False False]
# [False False True True]
# [ True True True True]]
print("a[mask]:", a[mask]) # Ausgabe: a[mask]: [ 6 7 8 9 10 11]
# Boolesche Indizierung mit Zuweisung
a[a < 5] = 0
print("Nach a[a < 5] = 0:")
print(a)
# Ausgabe:
# [[ 0 0 0 0]
# [ 0 5 6 7]
# [ 8 9 10 11]]Unterscheide das Lesen einer Auswahl von einer Zuweisung. selected = a[mask] erzeugt eine Kopie, doch a[a < 5] = 0 schreibt direkt an die ausgewählten Positionen in a. Der Wert 5 bleibt erhalten, weil die Bedingung < 5 und nicht <= 5 lautet.
Fancy Indexing
Fancy Indexing ist eine gebräuchliche Bezeichnung für Advanced Indexing mit Integern. Damit kannst du Positionen neu anordnen, wiederholen oder das Ergebnis entsprechend der Form eines Indexarrays aufbauen.
import numpy as np
# Array zur Demonstration
a = np.array([10, 20, 30, 40, 50, 60])
print("Array:", a) # Ausgabe: Array: [10 20 30 40 50 60]
# Fancy Indexing mit einer Indexliste
indices = [0, 2, 4, 1]
print("Indizes:", indices) # Ausgabe: Indizes: [0, 2, 4, 1]
print("a[indices]:", a[indices]) # Ausgabe: a[indices]: [10 30 50 20]
# Fancy Indexing mit einem NumPy-Array
np_indices = np.array([5, 1, 3, 1, 0])
print("NumPy-Indizes:", np_indices) # Ausgabe: NumPy-Indizes: [5 1 3 1 0]
print("a[np_indices]:", a[np_indices]) # Ausgabe: a[np_indices]: [60 20 40 20 10]
# Fancy Indexing mit einem 2D-Indexarray
indices_2d = np.array([[0, 1], [2, 3]])
print("2D-Indizes:")
print(indices_2d)
# Ausgabe:
# [[0 1]
# [2 3]]
print("a[indices_2d]:")
print(a[indices_2d])
# Ausgabe:
# [[10 20]
# [30 40]]In einem zweidimensionalen Array können Integer-Indizes ganze Zeilen auswählen oder Zeilen- und Spaltenkoordinaten elementweise paaren:
import numpy as np
# 2D-Array zur Demonstration
a = np.arange(24).reshape(4, 6)
print("2D-Array:")
print(a)
# Ausgabe:
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
# Fancy Indexing für bestimmte Zeilen
row_indices = [0, 2, 3]
print("a[row_indices, :]:")
print(a[row_indices, :])
# Ausgabe:
# [[ 0 1 2 3 4 5]
# [12 13 14 15 16 17]
# [18 19 20 21 22 23]]
# Fancy Indexing für bestimmte Elemente
row_idx = [0, 1, 2, 3]
col_idx = [1, 2, 3, 4]
print("a[row_idx, col_idx]:", a[row_idx, col_idx]) # Ausgabe: a[row_idx, col_idx]: [ 1 8 15 22]
# Kombination aus Fancy Indexing und Slicing
print("a[[0, 2], 1:4]:")
print(a[[0, 2], 1:4])
# Ausgabe:
# [[ 1 2 3]
# [13 14 15]]Daten in Arrays auswählen und neu anordnen
Mit denselben Auswahlregeln kannst du Daten ohne selbst geschriebene Schleifen filtern, Stichproben ziehen und neu anordnen.
Das folgende Beispiel zeigt Masken und Zuweisungen. In einer echten Analyse muss der Messkontext die Temperaturgrenzen und die Ersetzungsregel bestimmen:
import numpy as np
# Simulation von Temperatursensordaten
temperatures = np.array([22.5, 25.1, 19.8, 30.2, 18.5, 27.3, 31.1, 24.8])
print("Temperaturdaten:", temperatures) # Ausgabe: Temperaturdaten: [22.5 25.1 19.8 30.2 18.5 27.3 31.1 24.8]
# Normale Temperaturen filtern (20-28 Grad)
normal_temp_mask = (temperatures >= 20) & (temperatures <= 28)
normal_temps = temperatures[normal_temp_mask]
print("Normale Temperaturen:", normal_temps) # Ausgabe: Normale Temperaturen: [22.5 25.1 27.3 24.8]
# Extreme Temperaturen filtern
extreme_temp_mask = (temperatures < 20) | (temperatures > 30)
extreme_temps = temperatures[extreme_temp_mask]
print("Extreme Temperaturen:", extreme_temps) # Ausgabe: Extreme Temperaturen: [19.8 30.2 18.5 31.1]
# Extremwerte durch den Mittelwert ersetzen
mean_temp = temperatures[normal_temp_mask].mean()
temperatures_cleaned = temperatures.copy()
temperatures_cleaned[extreme_temp_mask] = mean_temp
print("Daten nach der Reinigung:", temperatures_cleaned) # Ausgabe: Daten nach der Reinigung: [22.5 25.1 24.925 24.925 24.925 27.3 24.925 24.8 ]Um eine Stichprobe mit demselben Generator und derselben NumPy-Version zu wiederholen, gibst du einem lokalen Generator einen festen Seed:
import numpy as np
# Simulationsdatensatz
data = np.arange(100).reshape(10, 10)
print("Form des Datensatzes:", data.shape) # Ausgabe: Form des Datensatzes: (10, 10)
# Zufällige Zeilenstichprobe mit lokalem Generator
rng = np.random.default_rng(42)
sample_indices = rng.choice(10, size=5, replace=False)
sample_indices.sort()
print("Stichprobenindizes:", sample_indices) # Ausgabe: Stichprobenindizes: [0 3 4 5 7]
sampled_data = data[sample_indices, :]
print("Form der Stichprobe:", sampled_data.shape) # Ausgabe: Form der Stichprobe: (5, 10)
print("Erste drei Spalten der Stichprobe:")
print(sampled_data[:, :3])
# Ausgabe:
# [[ 0 1 2]
# [30 31 32]
# [40 41 42]
# [50 51 52]
# [70 71 72]]
# Spaltenreorganisation
column_order = [9, 0, 5, 2, 7, 1, 8, 3, 6, 4]
reorganized_data = data[:, column_order]
print("Neu angeordnete erste Zeile:", reorganized_data[0, :]) # Ausgabe: Neu angeordnete erste Zeile: [9 0 5 2 7 1 8 3 6 4]