numpy
– eine Bibliothek für numerische Berechnungen¶
Numpy ist eine Python-Bibliothek mit Datentypen und Funktionen, die für numerische Berechnungen optimiert sind. Meist lassen sich solche Aufgaben zwar auch mit den normalen Python-Funktionen berechnen, gerade bei großen Zahlenmengen ist Numpy allerdings wesentlich schneller.
Numpy ist nicht im Python3-Standard enthalten und muss daher separat installiert werden :
sudo aptitude install python3-numpy
# oder easy_install3 numpy nach Installation von python3-setuptools
Der zentrale Objekttyp in Numpy ist das ndarray
(meist kurz „Array“
genannt), das viele Gemeinsamkeiten mit der normalen Liste aufweist. Ein
wesentlicher Unterschied besteht allerdings darin, dass alle im Array
gespeicherten Elemente den gleichen Objekttyp haben müssen. Die Größe von
Numpy-Arrays kann zudem nicht verändert werden, und es sind keine leeren Objekte
erlaubt. Durch derartige Eigenschaften können Numpy-Arrays vom
Python-Interpreter schneller durchlaufen werden. Darüber hinaus stellt Numpy
etliche grundlegende Funktionen bereit, um mit den Inhalten solcher Arrays zu
arbeiten und/oder Änderungen an solchen Arrays vorzunehmen.
Numpy-Arrays erstellen¶
Ein neues Numpy-Array kann folgendermaßen aus einer normalen Liste, deren Elemente alle den gleichen Datentyp haben müssen, erzeugt werden:
import numpy as np
nums = [1,2,3,4,5]
# Eindimensionales Array erstellen:
a = np.array(nums)
a
# Ergebnis: array([1, 2, 3, 4, 5])
Die beim Funktionsaufruf von array()
übergebene Liste kann auch aus mehreren
Teillisten bestehen, um beispielsweise zeilenweise die Werte einer Matrix als Numpy-Array zu speichern:
# Zweidimensionale Matrix erstellen
m1 = np.array([ [1,2,3], [4,5,6], [7,8,9] ])
m1
# Ergebnis:
# array([[1, 2, 3],
# [4, 5, 6],
# [7, 8, 9]])
Durch ein zweites Argument kann beim Aufruf der array()
-Funktion der
Datentyp der Elemente explizit festgelegt werden. Beispielsweise könnten im
obigen Beispiel durch eine zusätzliche Angabe von dtype=float
die in der
Liste enthaltenen Integer-Werte automatisch in Gleitkomma-Zahlen umgewandelt
werden.
Da auch Matrizen voller Nullen oder Einsen häufig vorkommen, können diese
mittels der dafür vorgesehenen Funktionen zeros()
bzw. ones()
erzeugt
werden. Dabei wird als erstes Argument ein Tupel als Argument angegeben, welches
die Anzahl an Zeilen und Spalten der Matrix festlegt, sowie als zweites Argument
wiederum optional der Datentyp der einzelnen Elemente:
# 2x3-Matrix aus Nullen erstellen:
# Zweidimensionale Matrix erstellen
m2 = np.zeros( (2,3), int)
m2
# Ergebnis:
# array([[0, 0, 0],
# [0, 0, 0]])
Eindimensionale Arrays mittels arange()
und linspace()
Mittels der Funktion arange()
kann ein (eindimensionales) Numpy-Array auf
Grundlage eines Zahlenbereichs erstellt werden:
# Numpy-Array aus Zahlenbereich mit angegebener Schrittweite erstellen:
# Syntax: np.arange(start, stop, step)
r = np.arange(0, 10, 0.1)
r
# Ergebnis:
# array([ 0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ,
# 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2. , 2.1,
# 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3. , 3.1, 3.2,
# 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4. , 4.1, 4.2, 4.3,
# 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5. , 5.1, 5.2, 5.3, 5.4,
# 5.5, 5.6, 5.7, 5.8, 5.9, 6. , 6.1, 6.2, 6.3, 6.4, 6.5,
# 6.6, 6.7, 6.8, 6.9, 7. , 7.1, 7.2, 7.3, 7.4, 7.5, 7.6,
# 7.7, 7.8, 7.9, 8. , 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7,
# 8.8, 8.9, 9. , 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8,
# 9.9])
Die Funktion arange()
verhält sich also genauso wie die Funktion
range(), liefert allerdings ein Numpy-Array mit den
entsprechenden Werten als Ergebnis zurück. [1]
Eine zweite, sehr ähnliche Möglichkeit zur Erstellung eines Numpy-Arrays bietet
die Funktion linspace()
: Bei dieser wird allerdings die Anzahl der Schritte
zwischen dem Start- und dem Endwert angegeben; die Schrittweite wird dann
automatisch berechnet.
# Numpy-Array aus Zahlenbereich mit angegebener Listen-Länge erstellen:
# Syntax: np.arange(start, stop, num)
l = np.linspace(0, 10, 100, endpoint=True)
l
# Ergebnis:
# array([ 0. , 0.1010101 , 0.2020202 , 0.3030303 ,
# 0.4040404 , 0.50505051, 0.60606061, 0.70707071,
# 0.80808081, 0.90909091, 1.01010101, 1.11111111,
# 1.21212121, 1.31313131, 1.41414141, 1.51515152,
# 1.61616162, 1.71717172, 1.81818182, 1.91919192,
# 2.02020202, 2.12121212, 2.22222222, 2.32323232,
# 2.42424242, 2.52525253, 2.62626263, 2.72727273,
# 2.82828283, 2.92929293, 3.03030303, 3.13131313,
# 3.23232323, 3.33333333, 3.43434343, 3.53535354,
# 3.63636364, 3.73737374, 3.83838384, 3.93939394,
# 4.04040404, 4.14141414, 4.24242424, 4.34343434,
# 4.44444444, 4.54545455, 4.64646465, 4.74747475,
# 4.84848485, 4.94949495, 5.05050505, 5.15151515,
# 5.25252525, 5.35353535, 5.45454545, 5.55555556,
# 5.65656566, 5.75757576, 5.85858586, 5.95959596,
# 6.06060606, 6.16161616, 6.26262626, 6.36363636,
# 6.46464646, 6.56565657, 6.66666667, 6.76767677,
# 6.86868687, 6.96969697, 7.07070707, 7.17171717,
# 7.27272727, 7.37373737, 7.47474747, 7.57575758,
# 7.67676768, 7.77777778, 7.87878788, 7.97979798,
# 8.08080808, 8.18181818, 8.28282828, 8.38383838,
# 8.48484848, 8.58585859, 8.68686869, 8.78787879,
# 8.88888889, 8.98989899, 9.09090909, 9.19191919,
# 9.29292929, 9.39393939, 9.49494949, 9.5959596 ,
# 9.6969697 , 9.7979798 , 9.8989899 , 10. ])
Setzt man im obigen Beispiel endpoint=False
, so ist das mit linspace()
erzeugte Array l
mit dem Array r
aus dem vorherigen Beispiel identisch.
Inhalte von Numpy-Arrays abrufen und verändern¶
Entspricht ein Numpy-Array einem eindimensionalen Vektor, so kann auf die einzelnen Elemente in gleicher Weise wie bei einer Liste zugegriffen werden:
nums = [1,2,3,4,5]
a = np.array(nums)
a[3]
# Ergebnis: 4
a[-1]
# Ergebnis: 5
Als positive Indizes sind Werte zwischen i >= 0
und i < len(array)
möglich; sie liefern jeweils den Wert des i+1
-ten Listenelements als
Ergebnis zurück. Für negative Indizes sind Werte ab i <= -1
möglich; sie
liefern jeweils den Wert des i
-ten Listenelements – vom Ende der Liste her
gerechnet – als Ergebnis zurück. Die Indizierung kann ebenso genutzt werden, um
den Inhalt des Arrays an einer bestimmten Stelle zu verändern:
a[-1] = 10
a
# Ergebnis: array([1, 2, 3, 4, 10])
Um auf Zahlenbereiche innerhalb eines Numpy-Arrays zuzugreifen, können wiederum
– wie bei der Indizierung von Listen und Tupeln – so genannte Slicings genutzt werden.
Dabei wird innerhalb des Indexoperators []
der auszuwählende Bereich mittels
der Syntax start:stop
festgelegt, wobei für start
und stop
die
Index-Werte der Bereichsgrenzen eingesetzt werden:
r = np.arange(10)
# Intervall selektieren:
r[3:8]
# Ergebnis: array([3, 4, 5, 6, 7])
# Jedes zweite Element im angegebenen Intervall auswählen:
r[3:8:2]
# Ergebnis: array([3, 5, 7])
Wie üblich wird bei Slicings die untere Grenze ins Intervall mit eingeschlossen,
die obere nicht. Mit der Syntax start:stop:step
kann bei Slicings zudem
festgelegt werden, dass innerhalb des ausgewählten Zahlenbereichs nur jede durch
die Zahl step
bezeichnete Zahl ausgewählt wird. Wird für start
oder
step
kein Wert angegeben, so wird der ganze Bereich ausgewählt:
# Ab dem fünften Element (von hinten beginnend) jedes Element auswählen:
r[5::-1]
# Ergebnis: array([5, 4, 3, 2, 1, 0])
Slicings können bei Zuweisungen von neuen Werten auch auf der linken Seite des
=
-Zeichens stehen. Auf diese Weise kann bisweilen auf eine for
-Schleife
verzichtet und der Code somit lesbarer gemacht werden.
Um in mehrdimensionalen Numpy-Arrays Werte zu selektieren, wird folgende Syntax verwendet:
m = np.array([ [1,2,3], [4,5,6] ])
m
# Ergebnis:
# array([[1, 2, 3],
# [4, 5, 6]])
# Element in der zweiten Zeile in der dritten Spalte auswählen:
m[1][2]
# Ergebnis: 6
Bei Numpy-Arrays können die „Verschachtelungstiefen“ wie bei Listen durch eine
mehrfache Anwendung des Index-Operators []
aufgelöst werden; ebenso ist für
das obige Beispiel allerdings auch die Syntax m3[1,2]
erlaubt und auch
üblich. Bei der Auswahl eines Elements aus einer Matrix können also innerhalb
des Index-Operators die Zeile und Spalte durch ein Komma getrennt ausgewählt
werden; Slicings sind hierbei ebenfalls möglich.
Funktionen für Numpy-Arrays¶
Viele Funktionen wie die Betragsfunktion abs()
, die Wurzelfunktion
sqrt()
oder trigonometrische Funktionen wie sin()
, cos()
und
tan()
, die im math
-Modul definiert sind, existieren in ähnlicher Weise
auch im Numpy-Modul – mit dem Unterschied, dass sie auf Numpy-Arrays angewendet
werden können. Dabei wird die jeweilige mathematische Funktion auf jedes
einzelne Element des Arrays angewendet, und als Ergebnis ebenfalls ein Array mit
den entsprechenden Funktionswerten zurück gegeben. [2]
Ebenso können die gewöhnlichen Operationen +
, -
, *
und /
angewendet werden, um beispielsweise zu allen Elemente eines Numpy-Arrays eine
bestimmte Zahl zu addieren/subtrahieren oder um alle Elemente mit einer
bestimmten Zahl zu multiplizieren. Die Numpy-Funktionen erzeugen dabei stets
neue Numpy-Arrays, lassen die originalen Arrays also stets unverändert.
r = np.arange(10)
r
# Ergebnis: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
r+1
# Ergebnis: array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
r**2
# Ergebnis: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])
np.sqrt(r**4)
# Ergebnis: array([ 0, 1, 4, 9, 16, 25, 36, 49, 64, 81])
np.sin(r)
# Ergebnis: array([ 0. , 0.84147098, 0.90929743, 0.14112001, -0.7568025 ,
# -0.95892427, -0.2794155 , 0.6569866 , 0.98935825, 0.41211849])
Zusätzlich gibt es in Numpy Funktionen, die speziell für Zahlenreihen und
Matrizen vorgesehen sind. Beispielsweise kann mit der Numpy-Funktionen
argmin()
und argmax()
der Index des kleinsten und größten Elements in
einem Array gefunden werden. Wendet man diese Funktionen auf ein Matrix-Array
an, so erhält man diejenige Index-Nummer des kleinsten beziehungsweise größten
Elements, die sich bei einem eindimensionalen Array mit den gleichen Werten
ergeben würde. Ist man hingegen spalten- oder zeilenweise an den jeweiligen
Minima beziehungsweise Maxima interessiert, so kann beim Aufruf dieser beiden
Funktionen als zweites Argument axis=0
für eine spaltenweise Auswertung
oder axis=1
für eine zeilenweie Auswertung angegeben werden:
a = np.array( [3,1,2,6,5,4] )
m = np.array([ [3,1,2], [6,5,4] ])
np.argmin(a)
# Ergebnis: 1
np.argmin(m)
# Ergebnis: 1
np.argmin(m, axis=0)
# Ergebnis: array([0, 0, 0])
np.argmin(m, axis=1)
# Ergebnis: array([1, 2])
Für Matrix-Arrays existieren zusätzlich die Numpy-Funktionen dot()
,
inner()
und outer()
, mit deren Hilfe Multiplikationen von Matrizen beziehungsweise Vektoren durchgeführt werden können.
… to be continued …
Links
Anmerkungen:
[1] | Auch bei der Das optionale dritte Argument gibt, ebenso wie bei range(), die Schrittweite zwischen den beiden Zahlengrenzen an. Ist der Zahlenwert der unteren Bereichsgrenze größer als derjenige der oberen Bereichsgrenze, so muss ein negativer Wert als Schrittweite angegeben werden, andererseits bleibt das resultierende Array leer. |
[2] | Die gleichnamigen Funktionen aus dem math -Modul können also auf
einzelne Elemente eines Numpy-Arrays, nicht jedoch auf das ganze Array an
sich angewendet werden. Letzteres könnte man zwar beispielsweies mittels
einer for -Schleife erreichen, doch die Ausführung des Codes bei
Verwendung der Numpy-Varianten ist erheblich schneller. |