Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Numpy
  • 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.

Inhalt

Grundlagen

  • 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.

Arrays verhalten sich nicht wie Listen. Mathematischen Operationen werden komponentenweise auf die Elemente des Arrays angewendet.

array([ 2, 4, 6, 8, 10])
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

Fast alle mathematischen Operatoren aus Python funktionieren analog mit NumPy Arrays.

array([ 1, 4, 9, 16, 25])
array([ 1, 4, 27, 256, 3125])

Achtung: Bei besonderen Funktionen (cos, sin, exp, etc.) werden die NumPy Methoden benötigt, z.B. np.cos()!

array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362, 0.28366219])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[10], line 3
      1 import math
      2 # This doesn't work
----> 3 math.cos(x_arr)

TypeError: only length-1 arrays can be converted to Python scalars

Bei großen Datensätzen ist die Laufzeit relevant und NumPy ist einige Größenordnungen schneller:

322 μs ± 914 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
5.15 μs ± 23.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

Selbstgeschriebene Funktionen, die nur für eine Zahl geschrieben wurden, funktionieren oft ohne Änderung mit NumPy Arrays.

-8.125475224531307
array([ 2, 2, -6, -28, -70])

Das erlaubt es einem unter anderem sehr leicht physikalische Formeln auf seine Datenpunkte anzuwenden.

Arrays können beliebige Dimension haben:

array([[ 2, 4, 6], [ 8, 10, 12], [14, 16, 18]])

Das erlaubt es z.B. eine ganze Tabelle von gleichen Datentypen als Array abzuspeichern.

Mit Arrays sind auch Matrixoperationen möglich:

Elementweise Multiplikation:
 [[2 0]
 [0 4]]
Matrix Multiplikation:
 [[5 4]
 [3 4]]
Skalarprodukt von Vektoren:
 32

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.

Array a: 
	 a.ndim   1 
	 a.shape  (3,) 
	 a.size   3 
	 a.dtype  float64
Array b: 
	 b.ndim   2 
	 b.shape  (2, 3) 
	 b.size   6 
	 b.dtype  int64

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.

array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
array([[1., 1.], [1., 1.], [1., 1.], [1., 1.], [1., 1.]])
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
array([1.e-04, 1.e-03, 1.e-02, 1.e-01, 1.e+00, 1.e+01, 1.e+02, 1.e+03, 1.e+04, 1.e+05])

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.

<IPython.core.display.Image object>
[0 1 2 3 4 5 6 7 8 9]
np.int64(4)
array([1, 2, 3])
(np.int64(9), np.int64(8))
array([3, 4, 5, 6, 7])
array([0, 2, 4, 6, 8])
array([9, 8, 7, 6, 5, 4, 3, 2, 1, 0])
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], [30, 31, 32, 33, 34, 35, 36, 37, 38, 39]])
array([32, 33, 34, 35, 36, 37, 38])
array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29])
array([ 3, 13, 23, 33])
(4, 10)
<IPython.core.display.Image object>

Ausgewählten Elementen kann man auch direkt einen Wert zuweisen.

array([[ 0, 1, 2, 0, 4, 5, 6, 7, 8, 9], [10, 11, 12, 0, 14, 15, 16, 17, 18, 19], [20, 21, 22, 0, 24, 25, 26, 27, 28, 29], [30, 31, 32, 0, 34, 35, 36, 37, 38, 39]])

Man kann Indexing auch gleichzeitig auf der linken und rechten Seite benutzen.

array([[ 3, 1, 2, 0, 4, 5, 6, 7, 8, 9], [ 4, 11, 12, 0, 14, 15, 16, 17, 18, 19], [ 5, 21, 22, 0, 24, 25, 26, 27, 28, 29], [ 6, 31, 32, 0, 34, 35, 36, 37, 38, 39]])

Transponieren des Arrays kehrt die Reihenfolge der Indizes um.

array([[ 3, 1, 2, 0, 4, 5, 6, 7, 8, 9], [ 4, 11, 12, 0, 14, 15, 16, 17, 18, 19], [ 5, 21, 22, 0, 24, 25, 26, 27, 28, 29], [ 6, 31, 32, 0, 34, 35, 36, 37, 38, 39]])
array([[ 3, 4, 5, 6], [ 1, 11, 21, 31], [ 2, 12, 22, 32], [ 0, 0, 0, 0], [ 4, 14, 24, 34], [ 5, 15, 25, 35], [ 6, 16, 26, 36], [ 7, 17, 27, 37], [ 8, 18, 28, 38], [ 9, 19, 29, 39]])
y 	Shape: (4, 10) 
y.T 	Shape: (10, 4)

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.

[0.  0.2 0.4 0.6 0.8 1.  1.2 1.4 1.6 1.8 2. ]
[False False False False False  True  True  True  True  True  True]
[1.  1.2 1.4 1.6 1.8 2. ]
[1.  1.2 1.4 1.6 1.8 2. ]

Reduzieren von Arrays

Viele Rechenoperationen reduzieren ein Array auf einen einzelnen Wert.

array([[ 3, 1, 2, 0, 4, 5, 6, 7, 8, 9], [ 4, 11, 12, 0, 14, 15, 16, 17, 18, 19], [ 5, 21, 22, 0, 24, 25, 26, 27, 28, 29], [ 6, 31, 32, 0, 34, 35, 36, 37, 38, 39]])

So z.B. die Summe aller Elemente oder die Multiplikation.

np.int64(666)
np.int64(0)
np.int64(6652872369767448576)

Bei vielen solchen Methoden kann die Dimension mit angegeben werden.

array([ 45, 126, 207, 288])
array([ 360, 7161, 16896, 0, 45696, 65625, 89856, 118881, 153216, 193401])

Auch Mittelwert und Standardabweichung der Einträge kann einfach bestimmt werden.

np.float64(16.65)
np.float64(12.590770429167549)

Oft wird im Praktikum aber nach der Unsicherheit des Mittelwerts gesucht.

np.float64(0.9574271077563381)

Dafür braucht man auch den Schätzer der Standardabweichung.

np.float64(3.0276503540974917)

Um die Differenzen zwischen benachbarten Elementen herauszufinden, kann die Funktion np.diff() genutzt werden.

z: [ 0  1  4  9 16 25 36 49 64 81]
array([ 1, 3, 5, 7, 9, 11, 13, 15, 17])

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().

Um den Inhalt der erstellten Datei zu öffnen, kann man analog zu Aufgabe 1-python/6-readwrite, die open-Funktion benutzen.

0.000000000000000000e+00 1.000000000000000000e+00 2.000000000000000000e+00 3.000000000000000000e+00 4.000000000000000000e+00 5.000000000000000000e+00 6.000000000000000000e+00 7.000000000000000000e+00 8.000000000000000000e+00 9.000000000000000000e+00 1.000000000000000000e+01
0.000000000000000000e+00 1.000000000000000056e-01 2.000000000000000111e-01 3.000000000000000444e-01 4.000000000000000222e-01 5.000000000000000000e-01 6.000000000000000888e-01 7.000000000000000666e-01 8.000000000000000444e-01 9.000000000000000222e-01 1.000000000000000000e+00

Für eine schönere Formatierung der Daten kann man auch np.column_stack() benutzen.

0.000000000000000000e+00 0.000000000000000000e+00
1.000000000000000000e+00 1.000000000000000056e-01
2.000000000000000000e+00 2.000000000000000111e-01
3.000000000000000000e+00 3.000000000000000444e-01
4.000000000000000000e+00 4.000000000000000222e-01
5.000000000000000000e+00 5.000000000000000000e-01
6.000000000000000000e+00 6.000000000000000888e-01
7.000000000000000000e+00 7.000000000000000666e-01
8.000000000000000000e+00 8.000000000000000444e-01
9.000000000000000000e+00 9.000000000000000222e-01
1.000000000000000000e+01 1.000000000000000000e+00

Am besten sollte aber auch immer erklären werden, was abspeichert wird:

# n x
0.000000000000000000e+00 0.000000000000000000e+00
1.000000000000000000e+00 1.000000000000000056e-01
2.000000000000000000e+00 2.000000000000000111e-01
3.000000000000000000e+00 3.000000000000000444e-01
4.000000000000000000e+00 4.000000000000000222e-01
5.000000000000000000e+00 5.000000000000000000e-01
6.000000000000000000e+00 6.000000000000000888e-01
7.000000000000000000e+00 7.000000000000000666e-01
8.000000000000000000e+00 8.000000000000000444e-01
9.000000000000000000e+00 9.000000000000000222e-01
1.000000000000000000e+01 1.000000000000000000e+00

(array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10.]), array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ]))

Um die Datentypen beim Speichern zu erhalten, muss das Keyword Argument fmt, wie im folgenden Beispiel gezeigt, angegeben werden.

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.

array([( 0, 0. ), ( 1, 0.1), ( 2, 0.2), ( 3, 0.3), ( 4, 0.4), ( 5, 0.5), ( 6, 0.6), ( 7, 0.7), ( 8, 0.8), ( 9, 0.9), (10, 1. )], dtype=[('n', '<i8'), ('x', '<f8')])
(array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]), (11,), dtype([('n', '<i8'), ('x', '<f8')]))

Aufgaben 3, 4 und 5 können bearbeitet werden.