Mit Arrays in Python arbeiten
NumPy hilft Python, numerische Daten effizient zu verarbeiten. Python-Listen können gemischte Typen enthalten, während ein NumPy-Array normalerweise Werte eines gemeinsamen Datentyps kompakt speichert. Bei vektorisierten Rechnungen mit vielen Werten ist diese Darstellung oft schneller als eine entsprechende Python-Schleife.
Das zentrale Objekt ndarray ist ein n-dimensionaler Behälter fester Größe, dessen Elemente einen gemeinsamen Datentyp besitzen. Dadurch kann ein einziger Ausdruck dieselbe Operation auf das gesamte Array anwenden.
NumPy-Arrays bieten die folgenden Vorteile für die wissenschaftliche Programmierung:
- Effiziente numerische Schleifen in kompiliertem Maschinencode
- Vektorisierung ermöglicht Operationen auf ganzen Arrays ohne explizite Schleifen
- Kompakte Speicherung gleichartiger numerischer Werte
- Viele gebrauchsfertige mathematische Operationen
Vektorisierung bedeutet, eine Operation für das gesamte Array auszudrücken, statt jedes Element in einer Python-Schleife einzeln zu bearbeiten. Intern verarbeitet NumPy die Elemente weiterhin, führt die Schleife aber in optimiertem kompiliertem Code aus.
# Elementmultiplikation mithilfe der Python-Liste
x = [1, 2, 3, 4, 5]
y = [2, 3, 4, 5, 6]
z = []
for i in range(len(x)):
z.append(x[i] * y[i])
print("Listenergebnis:", z) # Ausgabe: Listenergebnis: [2, 6, 12, 20, 30]
# Elementmultiplikation mit NumPy
import numpy as np
x_np = np.array([1, 2, 3, 4, 5])
y_np = np.array([2, 3, 4, 5, 6])
z_np = x_np * y_np
print("NumPy-Ergebnis:", z_np) # Ausgabe: NumPy-Ergebnis: [ 2 6 12 20 30]Manuelle Erstellung von Arrays
Mit np.array() wird eine vorhandene Python-Datenstruktur in ein NumPy-Array umgewandelt.
Ein eindimensionales Array ist eine Folge von Werten entlang einer Achse. Wir können es mit np.array() aus einer Python-Liste erstellen.
import numpy as np
# 1D-Array aus einer Liste erstellen
a = np.array([0, 1, 2, 3])
print("1D-Array:", a) # Ausgabe: 1D-Array: [0 1 2 3]
print("Datentyp:", type(a)) # Ausgabe: Datentyp: <class 'numpy.ndarray'>
print("Shape:", a.shape) # Ausgabe: Shape: (4,)
print("Dimensionen:", a.ndim) # Ausgabe: Dimensionen: 1Ein zweidimensionales Array ähnelt einer Tabelle mit Zeilen und Spalten. Eine verschachtelte Liste liefert dafür die Werte.
import numpy as np
# 2D-Array aus einer verschachtelten Liste erstellen
a = np.array([[0, 1], [2, 3]])
print("2D-Array:")
print(a)
# Ausgabe:
# [[0 1]
# [2 3]]
print("Shape:", a.shape) # Ausgabe: Shape: (2, 2)
print("Dimensionen:", a.ndim) # Ausgabe: Dimensionen: 2
print("Elemente insgesamt:", a.size) # Ausgabe: Elemente insgesamt: 4Ein dreidimensionales Array lässt sich als Stapel von Tabellen vorstellen. Jede Ebene enthält Zeilen und Spalten, die zusätzliche Achse wählt eine Ebene aus.
import numpy as np
# 3D-Array erstellen
a = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]])
print("3D-Array:")
print(a)
# Ausgabe:
# [[[ 1 2 3]
# [ 4 5 6]]
# [[ 7 8 9]
# [10 11 12]]]
print("Shape:", a.shape) # Ausgabe: Shape: (2, 2, 3)
print("Axis 0 (planes):", a.shape[0]) # Ausgabe: Axis 0 (planes): 2
print("Axis 1 (rows):", a.shape[1]) # Ausgabe: Axis 1 (rows): 2
print("Axis 2 (columns):", a.shape[2]) # Ausgabe: Axis 2 (columns): 3Mehrdimensionale Struktur
| Dimension | Form | Struktur | Beispiel | Achse |
|---|---|---|---|---|
| Eindimensional | (4,) | Zahlenfolge in einer Zeile | [0, 1, 2, 3] | Achse für Elementindex |
| Zweidimensional | (2, 2) | Tabelle mit Zeilen und Spalten | [[0, 1], [2, 3]] | Achse für Zeilen, Achse für Spalten |
| Dreidimensional | (2, 2, 3) | Stapel aus Tabellen (Ebenen) | Ebenen mit jeweils Einträgen | Achse für die Tiefe, Achse für die Höhe, Achse für die Breite |
Je höher die Array-Dimension, desto komplexer ist die Datenstruktur, das Grundprinzip bleibt jedoch dasselbe. Jede Achse repräsentiert eine Dimension der Datenorganisation.
NumPy kann Listen, Tupel und verschachtelte Kombinationen beider Strukturen in Arrays umwandeln.
import numpy as np
# Aus einer Liste
arr_from_list = np.array([0, 1, 2, 3])
print("Aus einer Liste:", arr_from_list) # Ausgabe: Aus einer Liste: [0 1 2 3]
# Aus einem Tupel
arr_from_tuple = np.array((0, 1, 2, 3))
print("Aus einem Tupel:", arr_from_tuple) # Ausgabe: Aus einem Tupel: [0 1 2 3]
# Aus gemischten Werten, die in einen gemeinsamen Datentyp umgewandelt werden
arr_mixed = np.array([0, 1, 2.5, 3])
print("Aus gemischten Werten:", arr_mixed) # Ausgabe: Aus gemischten Werten: [0. 1. 2.5 3. ]
print("Automatischer Datentyp:", arr_mixed.dtype) # Ausgabe: Automatischer Datentyp: float64Funktionen zum Erstellen von Arrays
Jedes Element von Hand zu schreiben lohnt sich nur für sehr kleine Beispiele. NumPy bringt deshalb eigene Erzeugungsfunktionen mit, die ein Array aus einer Regel statt aus einer literalen Liste aufbauen, wodurch der Code kurz bleibt und die Form ausdrücklich dasteht. Die folgenden Funktionen bilden drei Gruppen: Arrays mit einem konstanten Wert, Arrays mit Zufallszahlen und Arrays nach einem mathematischen Muster.
Konstantwertfunktionen
Die Funktion np.ones() erzeugt ein Array, dessen Elemente alle den Wert haben. Das ist praktisch, wenn jedes Element denselben Anfangswert benötigt.
import numpy as np
# 1D-Array mit dem Wert 1
a = np.ones(3)
print("1D ones:", a) # Ausgabe: 1D ones: [1. 1. 1.]
# 2D-Array mit dem Wert 1
a = np.ones((2, 3))
print("2D ones:")
print(a)
# Ausgabe:
# [[1. 1. 1.]
# [1. 1. 1.]]
# 3D-Array mit dem Wert 1
a = np.ones((2, 2, 3))
print("3D ones shape:", a.shape) # Ausgabe: 3D ones shape: (2, 2, 3)
print("3D ones:")
print(a)
# Ausgabe:
# [[[1. 1. 1.]
# [1. 1. 1.]]
# [[1. 1. 1.]
# [1. 1. 1.]]]Neben np.ones() gibt es noch weitere Funktionen zum Erstellen von Arrays mit speziellen Mustern:
import numpy as np
# Array mit Nullwerten
a = np.zeros((2, 3))
print("Zeros array:")
print(a)
# Ausgabe:
# [[0. 0. 0.]
# [0. 0. 0.]]
# Identitätsarray (diagonal 1, andere 0)
a = np.eye(3, 3)
print("Identity matrix:")
print(a)
# Ausgabe:
# [[1. 0. 0.]
# [0. 1. 0.]
# [0. 0. 1.]]
# Diagonales Array mit bestimmten Werten
a = np.diag((1, 2, 3))
print("Diagonal array:")
print(a)
# Ausgabe:
# [[1 0 0]
# [0 2 0]
# [0 0 3]]Zufallsfunktionen
Mit dem Zufallszahlengenerator np.random.default_rng() erzeugst du Simulationsdaten. Derselbe Seed liefert mit demselben Generator und derselben NumPy-Version eine wiederholbare Folge. Die gleichverteilten Werte unten liegen in [0, 1): Null ist eingeschlossen, Eins ausgeschlossen.
import numpy as np
# Seed für reproduzierbare Ergebnisse festlegen
rng = np.random.default_rng(10)
# Array mit gleichverteilten Zufallswerten zwischen 0 und 1
a = rng.random((2, 3))
print("Random uniform [0,1):")
print(a)
# Ausgabe:
# [[0.95600171 0.20768181 0.82844489]
# [0.14928212 0.51280462 0.1359196 ]]
# Array mit Normalverteilung (Mittelwert=0, std=1)
a = rng.standard_normal(3)
print("Random normal:", a) # Ausgabe: Random normal: [0.84304257 0.85793655 0.47518364]
# Array mit zufälligen Ganzzahlen in einem bestimmten Bereich
a = rng.integers(1, 10, size=(2, 3))
print("Random integers [1,10):")
print(a)
# Ausgabe:
# [[5 9 3]
# [8 1 4]]Mathematische Funktionen
np.fromfunction übergibt Arrays mit Indexkoordinaten an deine Funktion. Hier erhält f(i, j) die Zeilenindizes in i und die Spaltenindizes in j. Die Addition i + j erfolgt elementweise: An Position [1, 2] steht deshalb 3.
import numpy as np
# Array mit Funktion erstellen
def f(i, j):
return i + j
# 2x3-Array mit Werten aus der Funktion f(i,j) = i + j
a = np.fromfunction(f, (2, 3))
print("Array aus Funktion f(i,j) = i + j:")
print(a)
# Ausgabe:
# [[0. 1. 2.]
# [1. 2. 3.]]
# Komplexere Funktion
def g(i, j):
return i * j + 1
b = np.fromfunction(g, (3, 3))
print("Array aus Funktion g(i,j) = i*j + 1:")
print(b)
# Ausgabe:
# [[1. 1. 1.]
# [1. 2. 3.]
# [1. 3. 5.]]Die Funktion np.empty reserviert Speicher, ohne die Elemente zu initialisieren. Die sichtbaren Speicherinhalte sind beliebig. Deshalb muss jedes Element einen Wert erhalten, bevor es gelesen wird. Verwende die Funktion nur, wenn das Array unmittelbar danach vollständig gefüllt wird.
import numpy as np
# Nicht initialisiertes Array erstellen
a = np.empty((3, 2))
a.fill(0) # Alle Elemente vor dem Lesen mit Werten belegen
print("Array nach dem Befüllen:")
print(a)
# Ausgabe:
# [[0. 0.]
# [0. 0.]
# [0. 0.]]
print("Shape:", a.shape) # Ausgabe: Shape: (3, 2)
print("Dtype:", a.dtype) # Ausgabe: Dtype: float64Arrays aus Sequenzen
Manche Arrays lassen sich leichter als Sequenz beschreiben denn als Regel für jedes einzelne Element: alle Werte zwischen zwei Grenzen oder eine feste Anzahl gleichmäßig verteilter Punkte. np.arange und np.linspace erzeugen solche Arrays, und der Unterschied liegt darin, wie das Ende der Sequenz festgelegt wird.
Funktion Arange in NumPy
Die Funktion np.arange ähnelt Pythons range(), gibt aber ein Array zurück und akzeptiert Gleitkommaargumente. Bei nicht ganzzahligen Schritten kann die Gleitkommarundung den letzten Wert schwerer vorhersehbar machen. Wenn die Anzahl der Punkte feststeht, ist np.linspace oft eindeutiger.
import numpy as np
# Array von 0 bis 4
a = np.arange(5)
print("arange(5):", a) # Ausgabe: arange(5): [0 1 2 3 4]
# Array mit Startwert, Endwert und Schrittweite
a = np.arange(1.5, 3., 0.5)
print("arange(1.5, 3., 0.5):", a) # Ausgabe: arange(1.5, 3., 0.5): [1.5 2. 2.5]
# Array mit einer Schrittweite, die Dezimalwerte erzeugt
a = np.arange(1.5, 4.)
print("arange(1.5, 4.):", a) # Ausgabe: arange(1.5, 4.): [1.5 2.5 3.5]
# Parameterdemonstration
print("\nParameter arange(start, end, step):")
print("- Startwert, Endwert und Schrittweite dürfen Gleitkommazahlen sein")
print("- Der Endwert ist nicht im Ergebnis enthalten")
print("- Die Standard-Schrittweite ist 1")
print("- Der Standard-Startwert ist 0")Funktion Linspace in NumPy
Im Gegensatz zu np.arange, das feste Schritte verwendet, unterteilt np.linspace einen Bereich in eine Anzahl gleichmäßig verteilter Punkte.
import numpy as np
# Fünf gleichmäßig verteilte Punkte zwischen 0 und 10 erstellen
a = np.linspace(0, 10, 5)
print("linspace(0, 10, 5):", a) # Ausgabe: linspace(0, 10, 5): [ 0. 2.5 5. 7.5 10. ]
# Elf gleichmäßig verteilte Punkte zwischen -1 und 1 erstellen
a = np.linspace(-1, 1, 11)
print("linspace(-1, 1, 11):", a)
# Ausgabe: linspace(-1, 1, 11): [-1. -0.8 -0.6 -0.4 -0.2 0. 0.2 0.4 0.6 0.8 1. ]
# Vergleich zwischen linspace und arange
print("\nUnterschied zwischen Linspace und Arange:")
print("linspace: Anzahl der Elemente vorgegeben, Abstand zwischen den Elementen wird berechnet")
print("arange: Schrittweite vorgegeben, Anzahl der Elemente ergibt sich aus den Grenzen")Vergleich von Arange und Linspace
Beide Funktionen bauen ein Array aus einem Bereich, und der übergebene Parameter entscheidet über den Unterschied. arange legt den Abstand zwischen den Elementen fest, linspace dagegen die Anzahl der Elemente.
| Aspekt | np.arange | np.linspace |
|---|---|---|
| Hauptparameter | start, stop, step | start, stop, num |
| Kontrolle | Abstand zwischen Elementen | Gesamtzahl der Elemente |
| Endpunkt | Ausgeschlossen | Enthalten (Standard) |
| Datentyp | Aus der Eingabe abgeleitet | Verwendet standardmäßig einen Gleitkommatyp. Mit dtype lässt sich ein anderer Typ wählen |
| Verwendung | Sequenz mit festem Abstand | Gleichmäßige Bereichseinteilung |
Grundfunktionen
Prüfe vor dem Umformen Elementzahl und Form. Das folgende Array hat zwei Zeilen und drei Spalten, also size gleich 6. Der ausdrücklich angegebene Datentyp int64 benötigt acht Byte pro Element.
import numpy as np
# Beispielarray erstellen
a = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.int64)
print("Array:")
print(a)
# Ausgabe:
# [[1 2 3]
# [4 5 6]]
print("Form:", a.shape) # Ausgabe: Form: (2, 3)
print("Größe (Elemente insgesamt):", a.size) # Ausgabe: Größe (Elemente insgesamt): 6
print("Ndim (Dimensionen):", a.ndim) # Ausgabe: Ndim (Dimensionen): 2
print("Dtype (Datentyp):", a.dtype) # Ausgabe: Dtype (Datentyp): int64
print("Elementgröße (Bytes pro Element):", a.itemsize) # Ausgabe: Elementgröße (Bytes pro Element): 8Beim Umformen mit reshape() muss die Elementzahl gleich bleiben: 3 * 4, 2 * 6 und 4 * 3 ergeben jeweils 12. Mit -1 lässt du eine fehlende Dimension berechnen. Je nach Speicheranordnung entsteht dabei eine View oder eine Kopie.
import numpy as np
# 1D-Array mit 12 Elementen
a = np.arange(12)
print("Ursprüngliches Array:", a) # Ausgabe: Ursprüngliches Array: [ 0 1 2 3 4 5 6 7 8 9 10 11]
# Auf 3x4 umformen
b = a.reshape(3, 4)
print("Reshape 3x4:")
print(b)
# Ausgabe:
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# Auf 2x6 umformen
c = a.reshape(2, 6)
print("Reshape 2x6:")
print(c)
# Ausgabe:
# [[ 0 1 2 3 4 5]
# [ 6 7 8 9 10 11]]
# Mit -1 umformen, um eine Dimension automatisch zu bestimmen
d = a.reshape(4, -1)
print("4x-1 umformen (automatisch):")
print(d)
# Ausgabe:
# [[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]]