{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Numerisches Rechnen mit NumPy/SciPy\n", "\n", "Die hier vorgestellten Bibliotheken erlauben,\n", "dass eine Variable als Zahlenwert mehr als nur einen einzelnen Skalar beinhaltet.\n", "Sie bieten eine hocheffiziente Verwaltung und Verarbeitung eines Arrays von Werten gleichen (homogoenen) Typs.\n", "Damit wird dem Schritt zu Vektoren, Matrizen und Tensoren Tür und Tor geöffnet,\n", "um numerische Berechnungen effizient ausdrücken zu können.\n", "\n", "Die Programmbibliothek [NumPy](http://docs.scipy.org/doc/numpy/user/index.html)\n", "liefert mit `numpy.ndarray` einen Rang-n Tensor Typ,\n", "der effizientes Rechnen mit Vektoren und Matritzen erlaubt.\n", "\n", "All diese Berechnungen auf Basis dieses `np.ndarray` ist gemeinsam,\n", "dass sie dank der zugrundeliegenden Vektorisierung sehr effizienter ablaufen.\n", "Für performanten (und häufig auch besser lesbaren) Code ist es daher immer notwendig,\n", "auf diese Operationen zurückzugreifen -- auch wenn sie anfangs etwas verwirrend sein mögen `:-)`\n", "\n", "Lit.: Stefan Van Der Walt, S. Chris Colbert, Gaël Varoquaux: *[The NumPy array: a structure for efficient numerical computation](http://arxiv.org/abs/1102.1523)*, Computing in Science and Engineering 13, 2 (2011) 22-3, [PDF](http://arxiv.org/pdf/1102.1523v1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Bibliothek `numpy` wird üblicherweise immer mit dem Kurznamen Alias **`np`** importiert:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Vektoren und Matritzen" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Beispiel**: Die Variablen $v$ und $w$ sollen einen Vektor aus $\\mathbb{R}^3$ repräsentieren.\n", "Die Addition und Multiplikation werden elementweise durchgeführt,\n", "während `.dot()` das Skalarprodukt (engl. dot product) durchführt.\n", "\n", "\\begin{equation}\n", "\\begin{aligned}\n", "\\texttt{v + w} &= \\left[ v_i + w_i \\right]_i \\\\\n", "\\texttt{v * w} &= \\left[ v_i \\cdot w_i \\right]_i \\\\\n", "\\texttt{v.dot(w)} &= \\sum_i v_i*w_i \\\\\n", "\\text{für} \\quad & v,\\,w\\;\\in\\;\\mathbb{R}^3\n", "\\end{aligned}\n", "\\end{equation}\n", "\n", "Jetzt definieren wir $v$ und $w$, wobei $v = (4,\\,3,\\,-1)$ sein soll und $w$ ein zufällig gewählter Vektor.\n", "Dann führen wir die Berechnungen durch. " ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [], "source": [ "v = np.array([4,3,-1]) # Konstruktion aus einer Python \"list\"\n", "w = np.random.rand(3) # 3 zufällige uniform verteilte Zahlen" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 4, 3, -1])" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0.70613368, 0.61589773, 0.31350427])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 4.70613368, 3.61589773, -0.68649573])" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v + w" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 3.29386632, 2.38410227, -1.31350427])" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v - w" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 2.82453471, 1.84769319, -0.31350427])" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v * w" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Das (generalisierte) Skalarprodukt von $v$ und $w$" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4.358723634005492" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.dot(w)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Der Typ von `v` ist das schon erwähnte `ndarray`" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "numpy.ndarray" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(v)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### dtype\n", "\n", "Die Typen der Zahlen in den jeweiligen `ndarray` Objekten ist homogen und kann mit `.dtype` abgerufen werden.\n", "Standardmäßig sind dies `int64` oder `float64`.\n", "Insbesondere bedeutet dies, dass es sich *nicht* um native Python-Integer Werte handelt und es daher einen Überlauf geben kann. [siehe dtype](http://docs.scipy.org/doc/numpy/reference/arrays.dtypes.html). \n", "Der große Vorteil ist, dass dadurch [vektorisierte](http://en.wikipedia.org/wiki/Array_programming) Berechnungen möglich sind und mit einer viel höheren Geschwindigkeit verarbeitet werden können." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "dtype('int64')" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v.dtype" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "dtype('float64')" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "w.dtype" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bei der Instanzierung eines `ndarray` kann der `dtype` explizit angegeben werden -- es kann hier z.B. der Python `object`-Typ gewält werden um mit `int`-Werten zu rechnen:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "dtype('O')" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "python_ints = np.array([11111111111111111131111111,\n", " 14441111111111111111111111],\n", " dtype=object)\n", "python_ints.dtype" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "25552222222222222242222222" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "python_ints.sum()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Neben diesen Grundoperationen, werden alle NumPy-spezifischen Funktionen automatisch über tensor-wertige Argumente ausgeführt.\n", "Das heißt beispielsweise,\n", "dass die $\\sin$-Funktion über einen Vektor $x := (1,2,3)$ ergibt wieder einen Vektor,\n", "dessen Einträge die numerischen Werte von $(\\sin(1),\\,\\sin(2),\\,\\sin(3))$ beinhalten." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0.84147098, 0.90929743, 0.14112001])" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = np.array([1,2,3])\n", "np.sin(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$(e^1,\\,e^2,\\,e^3)$" ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 2.71828183, 7.3890561 , 20.08553692])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.exp(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Matritzen (n-dim arrays)\n", "\n", "Verschachtelte Listen werden zu einer n x m Matrix instanziert." ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, -2, 3, 8],\n", " [ 4, 6, 9, -9],\n", " [-1, 0, 5, 2],\n", " [11, 13, 15, 16]])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = np.array([[ 1,-2, 3, 8],\n", " [ 4, 6, 9,-9],\n", " [-1, 0, 5, 2],\n", " [11,13,15,16]])\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Berechnung des Cosinus über alle Einträge der Matrix `m`:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0.54030231, -0.41614684, -0.9899925 , -0.14550003],\n", " [-0.65364362, 0.96017029, -0.91113026, -0.91113026],\n", " [ 0.54030231, 1. , 0.28366219, -0.41614684],\n", " [ 0.0044257 , 0.90744678, -0.75968791, -0.95765948]])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.cos(m)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Extrahieren einzelner Spalten/Zeilen und Elemente\n", "\n", "Der Doppelpunkt `:` steht hierbei für die gesamte Spalte, `n:m` für ein Intervall, wobei `n` oder `m` weggelassen werden können. Negative Werte werden vom Ende weg gezählt.\n", "Dies ist eine Verallgemeinerung der Listen-Indizierung." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, -2, 3, 8],\n", " [ 4, 6, 9, -9],\n", " [-1, 0, 5, 2],\n", " [11, 13, 15, 16]])" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Element an Position (2, 2)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[2, 2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Setzen des Wertes an einer Position:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, -2, 3, 8],\n", " [ 4, 6, 9, -9],\n", " [ -1, 0, 987, 2],\n", " [ 11, 13, 15, 16]])" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[2, 2] = 987\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Spalte 0" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 1, 4, -1, 11])" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[:, 0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zeile 1" ] }, { "cell_type": "code", "execution_count": 22, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 4, 6, 9, -9])" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[1, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Letzte Spalte" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 8, -9, 2, 16])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[:, -1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Auswahl von zwei Elementen: Zeile 2, Spalte 0 und 2" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ -1, 987])" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[2, [0, 2]]" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[11, 13, 15, 16]])" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[-1:]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Teilmatrix, vom Anfang bis zur vorletzten Zeile und vor-vorletzten Spalte\"" ] }, { "cell_type": "code", "execution_count": 26, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, -2],\n", " [ 4, 6],\n", " [-1, 0]])" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[:-1, :-2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die `.diagonal()` Funktion gibt die Diagonalelemente zurück." ] }, { "cell_type": "code", "execution_count": 27, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 1, 6, 987, 16])" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.diagonal()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ein doppelter Doppelpunkt `::` gibt für ein `n:m` Intervall zusätzlich eine Schrittweite an." ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, -2, 3, 8],\n", " [ -1, 0, 987, 2]])" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[::2, :]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Schrittweite kann auch negativ sein, z.B. zum Umdrehen der Richtung:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 8, 3, -2, 1],\n", " [ -9, 9, 6, 4],\n", " [ 2, 987, 0, -1],\n", " [ 16, 15, 13, 11]])" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[:, ::-1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Views\n", "\n", "Eine wichtige Eigenschaft dieser Extraktionen ist, dass sie keine Kopie der Daten liefern.\n", "Dies ist im Allgemeinen schlecht, da es Zeit kostet und unnötigen Speicherplatz verbraucht.\n", "\n", "Daher wirken sich Änderungen an diesen \"Ansichten\" auf die Originaldaten aus -- was das folgende Beispiel verdeutlicht.\n", "\n", "Möchte man tatsächlich eine Kopie haben, so gibt es die `.copy()` Methode." ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "orig = np.array([[1, 2], [3, 4]])\n", "orig" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Kopie\n", "copy = orig.copy()" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([2, 4])" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# View der zweiten Spalte, als 1-dim Array\n", "view = orig[:, 1]\n", "view" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zweites Element" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "4" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "view[1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zuweisen des Wertes `99` an das zweite Element des Vektors `view`." ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": true }, "outputs": [], "source": [ "view[1] = 99" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 2, 99])" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "view" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`orig` hat *ebenfalls* (!) die `99` in den Daten." ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, 2],\n", " [ 3, 99]])" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "orig" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... copy aber nicht:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "copy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Transponieren" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, 4, -1, 11],\n", " [ -2, 6, 0, 13],\n", " [ 3, 9, 987, 15],\n", " [ 8, -9, 2, 16]])" ] }, "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Skalarprodukt zweier Spalten" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "165" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[:, 0].dot(m[:, 1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`.ravel()` gibt alle der Matrix oder dem Tensor zugrundeliegende Werte zurück\n", "(je nach dem in welcher Reihenfolge die Werte gespeichert werden, also spaltenweise oder zeilenweise)" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 1, -2, 3, 8, 4, 6, 9, -9, -1, 0, 987, 2, 11,\n", " 13, 15, 16])" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.ravel()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Generieren von Vektoren/Matritzen\n", "\n", "Darüber hinaus gibt es einige hilfreiche Funktionen,\n", "um einen Raster für das Auswerten einer Funktion an Punkten zu ermöglichen." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`np.arange` ist ähnlich wie Python's `range` Funktion,\n", "liefert jedoch gleich `np.ndarray` Vektoren zurück." ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5])" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.arange(1, 5, .5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "10 gleichmäßig verteilte Punkte von 0 to 2" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0. , 0.22222222, 0.44444444, 0.66666667, 0.88888889,\n", " 1.11111111, 1.33333333, 1.55555556, 1.77777778, 2. ])" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linspace(0, 2, 10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "10 logarithmisch verteilte Punkte von $\\text{base}^{-1}$ nach $\\text{base}^{2}$ mit base = 10" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0.1 , 0.21544347, 0.46415888, 1. ,\n", " 2.15443469, 4.64158883, 10. , 21.5443469 ,\n", " 46.41588834, 100. ])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.logspace(-1, 2, 10, base=10)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Koordinatenmatritzen\n", "\n", "Zur Auswertung von mehrstelligen Funktionen (also über mehrere Achsen),\n", "kann ein entsprechendes Grid von Punkten aus zwei oder mehr Vektoren konstruiert werden." ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": true }, "outputs": [], "source": [ "xx, yy = np.meshgrid([1, 2, 3], [0, 10, 20])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`xx` listet alle x-Werte auf, die jeweils mit den ..." ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 3],\n", " [1, 2, 3],\n", " [1, 2, 3]])" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xx" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... entsprechenden y-Werten in `yy` korrespondieren:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 0, 0],\n", " [10, 10, 10],\n", " [20, 20, 20]])" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "yy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Also: `(1, 0), (2, 0), (3, 0), (1, 10), (2, 10), ...`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dies ist zur Auswertung von mehrstellige Funktionen sehr praktisch:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 2, 3, 4],\n", " [22, 23, 24],\n", " [42, 43, 44]])" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1 + xx + 2 * yy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Eine Indexmatrix ist ähnlich, liefert aber unmittelbar die (x, y)-Index Einträge der Positionen." ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": true }, "outputs": [], "source": [ "xx, yy = np.indices((3, 2))" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[0, 0],\n", " [1, 1],\n", " [2, 2]])" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "xx" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[0, 1],\n", " [0, 1],\n", " [0, 1]])" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "yy" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Shape\n", "\n", "Die Dimensionierung eines Vektors oder Matrix lässt sich jederzeit ändern.\n", "Das liegt daran, dass ein `np.ndarray` aus einem Vektor aller Werte und einer Information,\n", "wie lang die Zeilen bzw. Spalten sind besteht.\n", "Diese *Shape*-Information kann jederzeit geändert werden und damit ändert sich auch die Dimensionierung des Arrays -- es muss jedoch die Anzahl der Elemente gleich bleiben!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "1d-Vektor der Länge 25" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(25,)" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c = np.arange(25)\n", "c.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ändern der Rang-1 shape `(25,)` auf Rang-2 `(5, 5)`, also eine 5x5-Matrix mit 25 Elementen:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3, 4],\n", " [ 5, 6, 7, 8, 9],\n", " [10, 11, 12, 13, 14],\n", " [15, 16, 17, 18, 19],\n", " [20, 21, 22, 23, 24]])" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.shape = (5, 5)\n", "c" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "oder `.reshape((tupel))`, wobei `-1` verwendet werden kann um die Dimensionierung automatisch anzupassen." ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[0, 1, 2, 3],\n", " [4, 5, 6, 7]])" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Vektor mit 8 Elementen\n", "c = np.arange(8) \n", "# Umwandlung zu einer Matrix mit 4 Spalten\n", "c = c.reshape((-1, 4)) \n", "c" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(2, 4)" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.shape" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.ndim" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rang 3, mit 2x2x2 Elementen:" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[[0, 1],\n", " [2, 3]],\n", "\n", " [[4, 5],\n", " [6, 7]]])" ] }, "execution_count": 56, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.shape = (2, 2, 2)\n", "c" ] }, { "cell_type": "code", "execution_count": 57, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 57, "metadata": {}, "output_type": "execute_result" } ], "source": [ "c.ndim" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tipp: Instanzierung und reshaping kann leicht kombiniert werden:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[-2. , -1.5, -1. ],\n", " [-0.5, 0. , 0.5],\n", " [ 1. , 1.5, 2. ]])" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linspace(-2, 2, 9).reshape((-1, 3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Einfügen einer neuen Achse\n", "\n", "Manchmal bietet sich aus rechnerischen Gründen an, einen Vektor zu einer `n x 1`-Matrix zu verwandeln.\n", "Dies -- und andere Redimensionierungen, die eine neue Achse einfügen -- können mit `np.newaxis` erledigt werden:" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(5,)" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = np.linspace(0, 1, 5)\n", "f.shape" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(5, 1)" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f2 = f[:, np.newaxis]\n", "f2.shape" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0. ],\n", " [ 0.25],\n", " [ 0.5 ],\n", " [ 0.75],\n", " [ 1. ]])" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f2" ] }, { "cell_type": "code", "execution_count": 62, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(5, 1)" ] }, "execution_count": 62, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f2.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Zusammenfügen\n", "\n", "Bestehenden Vektoren und Matritzen können mittels `r_` und `c_` Operatoren zusammengefügt werden." ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "collapsed": false }, "outputs": [], "source": [ "a = np.arange(10)\n", "b = np.arange(100, 110)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zeilenweise mit `r_` (für \"row\")" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100, 101, 102,\n", " 103, 104, 105, 106, 107, 108, 109])" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.r_[a, b]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Spaltenweise mit `c_` (für \"column\")" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 100, 100],\n", " [ 1, 101, 101],\n", " [ 2, 102, 102],\n", " [ 3, 103, 103],\n", " [ 4, 104, 104],\n", " [ 5, 105, 105],\n", " [ 6, 106, 106],\n", " [ 7, 107, 107],\n", " [ 8, 108, 108],\n", " [ 9, 109, 109]])" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.c_[a, b, b]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Broadcasting\n", "\n", "Eine der wichtigsten (und komplexeren) Techniken ist [\"Broadcasting\"](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html).\n", "Hierbei werden Skalare, Vektoren und Matritzen in Rechenoperationen gemischt.\n", "Das funktioniert so, dass im ersten Rang,\n", "der einem der Argumente fehlt,\n", "alle Werte auf die Art wiederholt werden,\n", "sodass die Dimensionierung in diesem Rang passt.\n", "\n", "Vereinfachtes Beispiel:\n", "Eine Addition des Vektors $[1,\\,2,\\,5]$ mit dem Skalar $10$ führt dazu, dass der Skalar intern wie ein $[10,\\,10,\\,10]$ Vektor behandelt wird und daher das Ergebnis $[11,\\,12,\\,15]$ ist." ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([11, 12, 15])" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.array([1,2,5]) + 10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "oder Matrix + Vektor" ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3],\n", " [ 4, 5, 6, 7],\n", " [ 8, 9, 10, 11],\n", " [12, 13, 14, 15]])" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.arange(16).reshape((4, 4))\n", "a" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ -1, 0, 10, 100])" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = np.array([-1, 0, 10, 100])\n", "b" ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ -1, 1, 12, 103],\n", " [ 3, 5, 16, 107],\n", " [ 7, 9, 20, 111],\n", " [ 11, 13, 24, 115]])" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Setzen einer ganzen Zeile:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1, -2, 3, 8],\n", " [ 4, 6, 9, -9],\n", " [ -1, 0, 987, 2],\n", " [777, 777, 777, 777]])" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m[-1, :] = 777\n", "m" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bei der vorhergehenden Addition wird der \"horizontale\" `b`-Vektor entlang der ersten Dimension der Matrix `a` (also zeilenweise) vervielfacht. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Kombination mit `np.newaxis` lassen sich \"äußere\" Operationen durchführen:\n", "Hier wird ein Vektor zu einer 4x1-Matrix verändert und dann addiert." ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([0, 1, 2, 3])" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.arange(4)\n", "a" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[0],\n", " [1],\n", " [2],\n", " [3]])" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = a[:, np.newaxis]\n", "b" ] }, { "cell_type": "code", "execution_count": 73, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[0, 1, 2, 3],\n", " [1, 2, 3, 4],\n", " [2, 3, 4, 5],\n", " [3, 4, 5, 6]])" ] }, "execution_count": 73, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a + b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hier werden also, damit es sich \"ausgeht\", **beide** Vektoren `a` und `b` entlang der jeweils anderen Achse vervielfacht." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Multiplikation eines Tensors 3-ter Stufe mit einem Vektor" ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[[0, 1],\n", " [2, 3]],\n", "\n", " [[4, 5],\n", " [6, 7]]])" ] }, "execution_count": 74, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.arange(8)\n", "a.shape = (2,2,2)\n", "a" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 1, 11])" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "b = np.array([1,11])\n", "b" ] }, { "cell_type": "code", "execution_count": 76, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[[ 0, 11],\n", " [ 2, 33]],\n", "\n", " [[ 4, 55],\n", " [ 6, 77]]])" ] }, "execution_count": 76, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a * b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... und deren (generalisiertes) Skalarprodukt ergibt eine 2x2-Matrix:" ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[11, 35],\n", " [59, 83]])" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.dot(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Methoden auf Arrays\n", "\n", "In der Praxis werden häufig Funktionen auf Vektoren oder Matrizen angewendet.\n", "Siehe auch [Numpy Routines](http://docs.scipy.org/doc/numpy/reference/routines.html)" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 5, 6, -1, 5],\n", " [ 1, 1, 1, 1],\n", " [ 0, -5, 10, 2]])" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m = np.array([[5, 6, -1, 5],\n", " [1, 1, 1, 1],\n", " [0,-5, 10, 2]])\n", "m" ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "26" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.sum()" ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 6, 2, 10, 8])" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.sum(axis=0)" ] }, { "cell_type": "code", "execution_count": 81, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([15, 4, 7])" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.sum(axis=1)" ] }, { "cell_type": "code", "execution_count": 82, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "-5" ] }, "execution_count": 82, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.min()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`m.ptp` steht für \"peak-to-peak\", gibt also den Wertebereich an.\n", "Hier wird außerdem mit `axis=0` nur entlang der Zeilen gearbeitet." ] }, { "cell_type": "code", "execution_count": 83, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 5, 11, 11, 4])" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "m.ptp(axis=0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lineare Algebra\n", "\n", "Die Submodule [numpy.linalg](http://docs.scipy.org/doc/numpy/reference/routines.linalg.html) und\n", "[scipy.linalg](http://docs.scipy.org/doc/scipy/reference/tutorial/linalg.html)\n", "beinhalten diverse Routinen für lineare Algebra." ] }, { "cell_type": "code", "execution_count": 84, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import numpy.linalg as LA" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Definition der Matrix $m$" ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "collapsed": false }, "outputs": [], "source": [ "m = np.array([[ 4, -1.1],\n", " [-2, 8 ]])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Eigenwerte & Eigenvektoren vom $m$" ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[ 3.51002008 8.48997992]\n", "[[-0.91347498 0.23795303]\n", " [-0.40689491 -0.97127666]]\n" ] } ], "source": [ "eigenvalues, eigenvectors = LA.eig(m)\n", "print(eigenvalues)\n", "print(eigenvectors)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Testen, ob der `0`-te Eigenwert/Vektor passt: beide Vektoren müssen bis auf Rundungsfehler gleich sein (das kontrolliert `np.allclose`)" ] }, { "cell_type": "code", "execution_count": 87, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.allclose(\n", " m.dot(eigenvectors[:,0]),\n", " eigenvalues[0] * eigenvectors[:,0]\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Determinante von $m$" ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "29.799999999999997" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LA.det(m)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Invertieren der Matrix $m$" ] }, { "cell_type": "code", "execution_count": 89, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0.26845638, 0.03691275],\n", " [ 0.06711409, 0.13422819]])" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LA.inv(m)" ] }, { "cell_type": "code", "execution_count": 90, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 1., 0.],\n", " [ 0., 1.]])" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "LA.inv(m).dot(m)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Optimierung und Nullstellensuche mit SciPy\n", "\n", "Ein wichtiger Zweig der Numerischen Mathematik ist Optimierung.\n", "Diese besteht aus einer Sammlung standardisierter Problemstellungen,\n", "welche unter eventuell gegebenen Nebenbedingungen einen Punkt $x \\in \\mathbb{R}^n$ suchen,\n", "wo eine gegebene Zielfunktion $f: \\mathbb{R}^n \\rightarrow \\mathbb{R}$ einen minimalen oder maximalen Wert annimmt.\n", "\n", "Problemstellungen dieser Art finden sich in mannigfaltigen Anwendungsgebieten\n", "und bringen diverse Varianten dieser Fragestellung hervor.\n", "Die folgenden Beispiele zeigen exemplarisch einige Varianten vor.\n", "\n", "Link: [scipy.optimize](http://docs.scipy.org/doc/scipy-dev/reference/optimize.html)" ] }, { "cell_type": "code", "execution_count": 91, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from scipy.optimize import minimize" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$f_1(x): \\mathbb{R}^3 \\rightarrow \\mathbb{R}$ wird optimiert." ] }, { "cell_type": "code", "execution_count": 92, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f1 = lambda x: (4 * x[0] - x[1])**2 + (x[1] - x[2])**2 * x[0] - x[2]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$x_0$ ist der Startwert in $\\mathbb{R}^3$" ] }, { "cell_type": "code", "execution_count": 93, "metadata": { "collapsed": false }, "outputs": [], "source": [ "x0 = [1., 2., 0.]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`bounds` ist die Box der Randbedingungen an $x$:" ] }, { "cell_type": "code", "execution_count": 94, "metadata": { "collapsed": false }, "outputs": [], "source": [ "bounds = [(-10, 10), (-10, 10), (0, 1)]" ] }, { "cell_type": "code", "execution_count": 95, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ " fun: -0.99999999999996092\n", " hess_inv: <3x3 LbfgsInvHessProduct with dtype=float64>\n", " jac: array([ 1.52100554e-06, -4.32986980e-07, -9.99999905e-01])\n", " message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'\n", " nfev: 64\n", " nit: 13\n", " status: 0\n", " success: True\n", " x: array([ 0.24999999, 0.9999998 , 1. ])" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "opti1 = minimize(f1, x0, bounds = bounds)\n", "opti1" ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([ 0.24999999, 0.9999998 , 1. ])" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x_opti = opti1[\"x\"]\n", "x_opti" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Eine höherdimensionale Funktion kann mittels der Standardalgorithmen \n", "\"[BFGS](http://en.wikipedia.org/wiki/BFGS_method)\"\n", "bzw.\n", "\"[L-BFGS-B](http://en.wikipedia.org/wiki/Limited-memory_BFGS)\" optimiert werden.\n", "SciPy liefert hier eine moderne und \"offizielle\" Fortranimplementation dieser Verfahren aus.\n", "\n", "Hier eine Formulierung für ein gesuchtes $x$, welches in jeder Dimension beschränkt ist (d.h. \"in einer Box liegt\").\n", "\n", "$$\\begin{align}\n", "\\min & \\quad f(x) && \\quad f:\\mathbb{R}^n \\rightarrow \\mathbb{R}\\\\\n", "\\text{s.t.} & \\quad x_{lb} \\leq x \\leq x_{ub} && \\quad x,\\,x_{lb},\\,x_{ub} \\in \\mathbb{R}^n\n", "\\end{align}$$\n", "\n", "Das Ziel ist das $x$ in dieser \"Box\" zu finden, welches $f(x)$ minimiert." ] }, { "cell_type": "code", "execution_count": 97, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from scipy.optimize import fmin_l_bfgs_b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mit diesen (wichtigsten) Argumenten:\n", "\n", "```\n", "func : callable f(x): Function to minimise.\n", "x0 : ndarray : Initial guess.\n", "approx_grad : bool : Whether to approximate the gradient numerically.\n", "bounds : list : ``(min, max)`` pairs for each element in ``x``\n", " defining the bounds on that parameter.\n", "```\n", "\n", "**Beispiel:**\n", "\n", "* Ein aufrufbares Objekt `f1`, welches mit dem Variablenvektor aufgerufen wird und den Wert zurückgeben soll.\n", "* Einem Startwert, z.b. `[0, 0]` wenn in $\\mathbb{R}^2$\n", "* `approx_grad = True`, wenn die Zielfunktion keinen Gradienten zurückgibt\n", "* und die Box: z.B `bounds = [(-5, 5), (-5, 5)]`" ] }, { "cell_type": "code", "execution_count": 98, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f1 = lambda x : x[0]**3 + (1 + x[1]**2) - (2 - x[0]) * x[1]\n", "x_opt, f_x_opt, info = fmin_l_bfgs_b(f1, \n", " x0=[0, 0],\n", " bounds=[(-5, 5), (-5, 5)],\n", " approx_grad=True)" ] }, { "cell_type": "code", "execution_count": 99, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Minimum: f([-5. 3.49999914]) = -136.250000'" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Minimum: f(%s) = %.6f\" % (x_opt, f_x_opt)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Nullstellensuche" ] }, { "cell_type": "code", "execution_count": 100, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from scipy.optimize import fsolve" ] }, { "cell_type": "code", "execution_count": 101, "metadata": { "collapsed": false }, "outputs": [], "source": [ "f2 = lambda x : 3 * x**3 - x**2 + 1" ] }, { "cell_type": "code", "execution_count": 102, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([-0.5981935])" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fsolve(f2, 1.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vektorwertige Funktion $f_3(x): \\mathbb{R}^2 \\rightarrow \\mathbb{R}^2$" ] }, { "cell_type": "code", "execution_count": 103, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from scipy.optimize import root" ] }, { "cell_type": "code", "execution_count": 104, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from numpy import sqrt\n", "f3 = lambda x : [(x[0] + x[1])**2 - 4, x[0] + sqrt(x[1])]" ] }, { "cell_type": "code", "execution_count": 105, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ " fjac: array([[-0.97680164, -0.21414609],\n", " [ 0.21414609, -0.97680164]])\n", " fun: array([ 2.07300843e-12, 1.27009514e-13])\n", " message: 'The solution converged.'\n", " nfev: 12\n", " qtf: array([ -8.12325364e-09, 1.26538374e-09])\n", " r: array([-4.8930465 , -3.96638873, 0.61326347])\n", " status: 1\n", " success: True\n", " x: array([-2., 4.])" ] }, "execution_count": 105, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f3_root = root(f3, [2., 1.])\n", "f3_root" ] }, { "cell_type": "code", "execution_count": 106, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([-2., 4.])" ] }, "execution_count": 106, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f3_root.x" ] } ], "metadata": { "kernelspec": { "display_name": "Anaconda (Python 3)", "language": "python", "name": "anaconda3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.1" } }, "nbformat": 4, "nbformat_minor": 0 }