Numpy

  • NumPy steht für Numerical Python und ist die Grundlage für wissenschaftliche Datenverarbeitung und 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.

In [1]:
%%javascript
$.getScript('https://kmahelona.github.io/ipython_notebook_goodies/ipython_notebook_toc.js')

Inhalt¶

Grundlagen¶

In [2]:
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.

In [3]:
x_arr = np.array([1, 2, 3, 4, 5])
In [4]:
x_list = [1, 2, 3, 4, 5]

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

In [5]:
2 * x_arr
Out[5]:
array([ 2,  4,  6,  8, 10])
In [6]:
2 * x_list
Out[6]:
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

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

In [7]:
x_arr**2
Out[7]:
array([ 1,  4,  9, 16, 25])
In [8]:
x_arr**x_arr
Out[8]:
array([   1,    4,   27,  256, 3125])

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

In [9]:
np.cos(x_arr)
Out[9]:
array([ 0.54030231, -0.41614684, -0.9899925 , -0.65364362,  0.28366219])
In [10]:
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:

In [11]:
%%timeit
x_pure = [42] * 10000
x_pure2 = [x**2 for x in x_pure]
1.43 ms ± 986 ns per loop (mean ± std. dev. of 7 runs, 1,000 loops each)
In [12]:
%%timeit 
x = np.full(10000, 42)
x2 = x**2
7.53 µs ± 7.27 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.

In [13]:
def poly(y):
    return y + 2 * y**2 - y**3

poly(np.pi)
Out[13]:
-8.125475224531307
In [14]:
poly(x_arr)
Out[14]:
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:

In [15]:
# two-dimensional array
y = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]])

# element-wise summation, like matrix summation
y + y
Out[15]:
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:

In [16]:
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)
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.

In [17]:
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}')
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.

In [18]:
np.zeros(10)
Out[18]:
array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
In [19]:
np.ones((5, 2))
Out[19]:
array([[1., 1.],
       [1., 1.],
       [1., 1.],
       [1., 1.],
       [1., 1.]])
In [20]:
np.linspace(0, 1, 11)
Out[20]:
array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1. ])
In [21]:
# like range() for arrays:
np.arange(0, 10)
Out[21]:
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
In [22]:
np.logspace(-4, 5, 10)
Out[22]:
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])

NumPy Indexing¶

NumPy erlaubt einem sehr bequem bestimmte Elemente aus einem Array auszuwählen und z.B. nur auf diesen Elementen Operationen auszuführen.