- NumPy steht für Numerical Python und ist die Grundlage für wissenschaftliche Datenverarbeitung
- NumPy stellt viele optimierte algebraische Methoden zur Verfügung
Motivation:
- Im Praktikum (und allgemein in der Physik) werden Datenpunkte gemessen, die anschließend ausgewertet werden
- NumPy ist eine Python-Bibliothek, die den Umgang mit Datenpunkten enorm vereinfacht
Die Dokumentation ist hier zu finden.
from IPython.display import Image
%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')
Inhalt¶
Grundlagen¶
import numpy as np
- Grunddatentyp von NumPy ist das n-dimensionale Array (numpy.ndarray)
- NumPy Arrays speichern Werte eines Datentyps in einem zusammenhängenden Speicherbereich, wodurch mathematische Operationen auf allen Werten des Arrays effizienter sind
- Die Effizienz in den Berechnungen kommt durch NumPys Nutzung von optimiertem C/Cython Code statt purem Python Code
Hier sind einige erste Beispiele zur Nutzung dieser Arrays.
x_arr = np.array([1, 2, 3, 4, 5])
x_list = [1, 2, 3, 4, 5]
Arrays verhalten sich nicht wie Listen. Mathematischen Operationen werden komponentenweise auf die Elemente des Arrays angewendet.
2 * x_arr
2 * x_list
Fast alle mathematischen Operatoren aus Python funktionieren analog mit NumPy Arrays.
x_arr**2
x_arr**x_arr
Achtung: Bei besonderen Funktionen (cos, sin, exp, etc.) werden die NumPy Methoden benötigt, z.B. np.cos()
!
np.cos(x_arr)
import math
# This doesn't work
# math.cos(x_arr)
Bei großen Datensätzen ist die Laufzeit relevant und NumPy ist einige Größenordnungen schneller:
%%timeit
x_pure = [42] * 10000
x_pure2 = [x**2 for x in x_pure]
%%timeit
x = np.full(10000, 42)
x2 = x**2
Selbstgeschriebene Funktionen, die nur für eine Zahl geschrieben wurden, funktionieren oft ohne Änderung mit NumPy Arrays.
def poly(y):
return y + 2 * y**2 - y**3
poly(np.pi)
poly(x_arr)
Das erlaubt es einem unter anderem, sehr leicht physikalische Formeln auf seine Datenpunkte anzuwenden.
Arrays können beliebige Dimension haben:
# two-dimensional array
y = np.array(
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
)
# element-wise summation, like matrix summation
y + y
Das erlaubt es z.B. eine ganze Tabelle von gleichen Datentypen als Array abzuspeichern.
Mit Arrays sind auch Matrixoperationen möglich:
A = np.array(
[
[1, 1],
[0, 1],
]
)
B = np.array(
[
[2, 0],
[3, 4],
]
)
# element-wise product
element_wise_product = A * B
print("Elementweise Multiplikation:\n", element_wise_product)
# matrix product
matrix_product = A @ B
print("Matrix Multiplikation:\n", matrix_product)
# vector scalar product
one_dim_vectors = np.array([1, 2, 3]).T @ np.array([4, 5, 6])
print("Skalarprodukt von Vektoren:\n", one_dim_vectors)
Eigenschaften von Arrays¶
NumPy-Arrays tragen neben den Daten noch zusätzliche Informationen über die Eigenschaften des Arrays.
Die Dimension eines Arrays kann mit der ndim
-Funktion abgerufen werden. In NumPy werden die Dimensionen von 0 aufsteigend durchnummeriert. Wird über einzelne Dimensionen eines Arrays gesprochen, werden im NumPy Kontext die Bezeichnungen Achse/Achsen (axis/axes) verwendet. Die Dimension ist also die Anzahl aller Achsen.
Die shape
-Funktion gibt in einem Tupel an, wie viele Elemente in jeder Dimension vorhanden sind.
Die Gesamtzahl der Elemente in einem Array können mit der size
-Funktion abgefragt werden.
Der Datentyp eines Arrays muss innerhalb des Arrays der gleiche sein. Um den Datentyp eines Arrays abzufragen gibt es die dtype
-Funktion.
a = np.array([1.5, 3.0, 4.2])
b = np.array(
[
[1, 2, 3],
[4, 5, 6],
]
)
print(
f"Array a: \n\t a.ndim {a.ndim} \n\t a.shape {a.shape} \n\t a.size {a.size} \n\t a.dtype {a.dtype}"
)
print(
f"Array b: \n\t b.ndim {b.ndim} \n\t b.shape {b.shape} \n\t b.size {b.size} \n\t b.dtype {b.dtype}"
)
Erstellen von Arrays¶
Es gibt viele nützliche Funktionen, die bei der Erstellung von Arrays helfen. Zum Verständnis der einzugebenden Argumente ist die NumPy Dokumentation zu empfehlen.
np.zeros(10)
np.ones((5, 2))
np.linspace(0, 1, 11)
# like range() for arrays:
np.arange(0, 10)
np.logspace(-4, 5, 10)
Aufgabe 1 kann bearbeitet werden.
NumPy Indexing¶
NumPy erlaubt einem sehr bequem bestimmte Elemente aus einem Array auszuwählen und z.B. nur auf diesen Elementen Operationen auszuführen.
Image(filename="images/Indexing1D.png")
x = np.arange(0, 10)
print(x)
# like lists:
x[4]
# all elements with indices ≥1 and <4:
x[1:4]
# negative indices count from the end
x[-1], x[-2]
# combination:
x[3:-2]
# step size
x[::2]
# trick for reversal: negative step
x[::-1]
y = np.array([x, x + 10, x + 20, x + 30])
y
# comma between indices
y[3, 2:-1]
# only one index ⇒ one-dimensional array
y[2]
# other axis: (`:` alone means the whole axis)
y[:, 3]
# inspecting the number of elements per axis:
y.shape
Image(filename="images/Indexing2D.png")
Ausgewählten Elementen kann man auch direkt einen Wert zuweisen.
y[:, 3] = 0
y
Man kann Indexing auch gleichzeitig auf der linken und rechten Seite benutzen.
y[:, 0] = x[3:7]
y
Transponieren des Arrays kehrt die Reihenfolge der Indizes um.
y
y.T
print(f"y \tShape: {y.shape} \ny.T \tShape: {y.T.shape}")
Aufgabe 2 kann bearbeitet werden.
Masken¶
Oft will man Elemente auswählen, die eine oder mehrere Bedingungen erfüllen. Hierzu wird eine Maske (Array aus True/False-Werten) mit der gleichen Dimension erstellt. Die Maske kann in eckigen Klammern übergeben werden.
a = np.linspace(0, 2, 11)
print(a)
# create a mask with the condition: element >= 1
mask = a >= 1
print(mask)
print(a[mask])
# do it in one step:
print(a[a >= 1])
Reduzieren von Arrays¶
Viele Rechenoperationen reduzieren ein Array auf einen einzelnen Wert.
y
So z.B. die Summe aller Elemente oder die Multiplikation.
np.sum(y)
np.prod(y)
np.prod(y[y != 0])
Bei vielen solchen Methoden kann die Dimension mit angegeben werden.
np.sum(y, axis=1) # sum of each row
np.prod(y, axis=0) # multiplication of each column
Auch Mittelwert und Standardabweichung der Einträge kann einfach bestimmt werden.
np.mean(y)
np.std(y)
Oft wird im Praktikum aber nach der Unsicherheit des Mittelwerts gesucht.
np.std(x, ddof=1) / np.sqrt(len(x))
Dafür braucht man auch den Schätzer der Standardabweichung.
np.std(x, ddof=1)
Um die Differenzen zwischen benachbarten Elementen herauszufinden kann die Funktion np.diff()
genutzt werden.
z = x**2
print("z ", z)
np.diff(z)
Input / Output¶
Um Datenpunkte aus einer Textdatei einzulesen wird die Funktion np.genfromtxt()
genutzt.
Sie gibt den Inhalt einer Textdatei als Array zurück.
Die Funktion, die Datenpunkte in eine Datei abspeichert, ist np.savetxt()
.
n = np.arange(11)
x = np.linspace(0, 1, 11)
np.savetxt("test.txt", [n, x])
Um den Inhalt der erstellten Datei zu öffnen, kann man analog zu Aufgabe 1-python/6-readwrite
, die open
-Funktion benutzen.
with open("test.txt") as f:
print(f.read())
Für eine schönere Formatierung der Daten kann man auch np.column_stack()
benutzen.
data = np.array([n, x])
np.savetxt("test.txt", np.column_stack([n, x]))
with open("test.txt") as f:
print(f.read())
Am besten sollte aber auch immer erklären werden, was abspeichert wird:
n = np.arange(11)
x = np.linspace(0, 1, 11)
# header schreibt eine Kommentarzeile in die erste Zeile der Datei
np.savetxt("test.txt", np.column_stack([n, x]), header="n x")
with open("test.txt") as f:
print(f.read())
a, b = np.genfromtxt("test.txt", unpack=True)
a, b
Um die Datentypen beim Speichern zu erhalten, muss das Keyword Argument fmt
, wie im folgenden Beispiel gezeigt, angegeben werden.
np.savetxt(
"test.txt",
np.column_stack([n, x]),
fmt=["%d", "%.4f"], # first column integer, second 4 digits float
delimiter=",",
header="n,x",
)
data = np.genfromtxt(
"test.txt",
dtype=None, # guess data types
delimiter=",",
names=True,
)
Das resultierende Array data
ist besonders, da es ein sogenanntes structured array
ist.
Dies ist ein NumPy Array in dem quasi mehrere Arrays in einem abgespeichert sind. Die einzelnen Arrays werden in der Dokumentation fields
genannt und haben jeweils einen zugeordneten Namen und einen Datentyp.
data
data["n"], data.shape, data.dtype
Aufgaben 3, 4 und 5 können bearbeitet werden.