diff --git a/3/Labo3.ipynb b/3/Labo3.ipynb new file mode 100644 index 0000000..89981e4 --- /dev/null +++ b/3/Labo3.ipynb @@ -0,0 +1,485 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Labo 3 Data Science : Numerical Python (numpy)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. Matrices als geneste lijsten" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Een matrix zou je in Python kunnen voorstellen als een geneste lijst. \n", + "Je kan op een eenvoudige manier elementen accesereren (via de indices, slicing), elementen wijzigen, deleten enz.." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "T = [[11, 12, 5, 2], [15, 6, 10, 15], [10, 8, 12, 5], [12,15,8,6]]\n", + "print(T[0])\n", + "print(T[1][2])\n", + "\n", + "for r in T:\n", + " for c in r:\n", + " print(c,end = \" \")\n", + " print()\n", + " \n", + "print('\\ninserting:' + str([0,5,11,13,6]))\n", + "#rij toevoegen\n", + "T.insert(2, [0,5,11,13,6])\n", + "\n", + "for r in T:\n", + " for c in r:\n", + " print(c,end = \" \")\n", + " print()\n", + "\n", + "print('\\nupdating:')\n", + "# wijzig de tweede rij naar [11,9,7]\n", + "T[2] = [11,9,7]\n", + "# het element op positie(0,3) naar 100\n", + "T[0][3]=100\n", + "\n", + "for r in T:\n", + " for c in r:\n", + " print(c,end = \" \")\n", + " print()\n", + "\n", + "print('\\ndeleting')\n", + "#verwijder de derde rij\n", + "del T[2]\n", + "#verwijder het element op postie(0,0)\n", + "del T[0][0]\n", + "for r in T:\n", + " for c in r:\n", + " print(c,end = \" \")\n", + " print()\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Oefening 1__ : Schrijf een Python-functie die een dambordmatrix van dimensie n genereert. Voorbeeld: dambordmatrix van dimensie 3:\n", + "\\begin{equation*}\n", + "\\begin{bmatrix}\n", + "0 & 1 & 0 \\\\\n", + "1 & 0 & 1 \\\\\n", + "0 & 1 & 0\n", + "\\end{bmatrix}\n", + "\\end{equation*}\n", + "Elke rij en elke kolom is een alternering van $0$ en$1$. Het is niet toegelaten om numpy te gebruiken !! \n", + "\n", + "_Tip:_ [1,2]*2 geeft [1,2,1,2].\n", + "De python-matrix kan je rechtstreeks visualiseren met __[matplotlib's pcolor](https://matplotlib.org/gallery/images_contours_and_fields/pcolor_demo.html#sphx-glr-gallery-images-contours-and-fields-pcolor-demo-py)__ " + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "from matplotlib.colors import LogNorm\n", + "import time\n", + "\n", + "def dam(n):\n", + " final = []\n", + " val = False\n", + " for x in range(n):\n", + " tmp = []\n", + " for y in range(n):\n", + " tmp.append(int(val))\n", + " val = not val\n", + " final.append(tmp)\n", + " return final\n", + "\n", + "plt.matshow(dam(5))\n", + "plt.show()\n", + "#plt.pcolor(dam(7))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. Matrices in numpy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Oefening 2__ :\n", + "Deze oefening vormt een opwarmer op NumPy. De __[Quickstart van NumPy](https://docs.scipy.org/doc/numpy/user/quickstart.html#quickstart-shape-manipulation)__ geeft voldoende info voor deze oefening.\n", + "* Definieer een klassieke Python-lijst met de gehele getallen van 0 t.e.m. 24.\n", + "* Zet deze lijst om naar een NumPy-array\n", + "* Herschik de elementen zodat het een 5x5 matrix wordt\n", + "* Print van deze matrix: het aantal dimensies, de dimensies (= shape) zelf en het datatype van de elementen\n", + "* Vermenigvuldig alle elementen met 2\n", + "* Gebruik slicing om\n", + " * de __laatste__ rij weer te geven\n", + " * van de eerste 2 rijen de __laatste__ 2 kolommen weer te geven\n", + " * alle __even__ rijen en kolommen weer te geven\n", + "* Toon de booleaanse matrix die aangeeft of de elementen deelbaar zijn door 7\n", + "* Gebruik deze booleaanse matrix om deze elementen op 0 te zetten\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "range(0, 25)\n", + "[ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n", + " 24]\n", + "[[ 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]]\n", + "2\n", + "(5, 5)\n", + "int32\n", + "[[ 0 2 4 6 8]\n", + " [10 12 14 16 18]\n", + " [20 22 24 26 28]\n", + " [30 32 34 36 38]\n", + " [40 42 44 46 48]]\n", + "\n", + "\n", + "[[40 42 44 46 48]]\n", + "\n", + "\n", + "[[ 6 8]\n", + " [16 18]]\n", + "\n", + "\n", + "[[12 16]\n", + " [32 36]]\n", + "[[ 0 0 0 0 0]\n", + " [ 0 0 14 0 0]\n", + " [ 0 0 0 0 28]\n", + " [ 0 0 0 0 0]\n", + " [ 0 42 0 0 0]]\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "\n", + "lijst = range(25)\n", + "print(lijst)\n", + "lijst = np.array(lijst)\n", + "print(lijst)\n", + "lijst = lijst.reshape(5,5)\n", + "print(lijst)\n", + "print(lijst.ndim)\n", + "print(lijst.shape)\n", + "print(lijst.dtype)\n", + "\n", + "lijst = lijst * 2\n", + "print(lijst)\n", + "print(\"\\n\")\n", + "print(lijst[-1:])\n", + "print(\"\\n\")\n", + "print(lijst[:2,-2:])\n", + "print(\"\\n\")\n", + "print(lijst[1::2,1::2])\n", + "print(\"\\n\")\n", + "temp = lijst % 7 == 0\n", + "print(temp*lijst)\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. Rekenen in numpy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Om te rekenen met matrices is de numpy module aangewezen wegens de efficiente manier waarop array operaties zonder loops afgehandeld worden (vectorization). Er wordt onderscheid gemaakt tussen een matrix (2dim) en een ndarray (n dimensies). \n", + "\n", + "Merk het verschil tussen de puntsgewijze vermenigvuldiging en de dot vermenigvuldiging, en het verschil van deze operatoren tussen de matrix en de ndarray. Merk al helemaal het verschil in de tijd nodig om de elementen te verdubbelen tussen Python-lists en NumPy-arrays (gebruik ipython magic functie %time)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "#vector\n", + "x = np.array([1,2])\n", + "\n", + "#matrix\n", + "m = np.mat( [[2,3], [3, 5]] )\n", + "\n", + "#array\n", + "y = np.array( [[1,2], [5, -1]] )\n", + "\n", + "print(x+x)\n", + "\n", + "print('\\n', y*y)\n", + "print(np.dot(y,y))\n", + "print(y@y)\n", + "\n", + "print('\\n', m*m)\n", + "print(np.dot(m,m))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "my_array = np.arange(1000000)\n", + "my_list = list(range(1000000))\n", + "%time for _ in range(10): my_arr2 = my_array * 2\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%time for _ in range(10): my_list2 = [x * 2 for x in my_list]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Oefening 3__ : Vraagstuk : 4 personen kopen elk respectivelijk volgende hoeveelheid paaseieren\n", + " * persoon 1 : 100g witte, 175gr bruine, 210gr zwarte\n", + " * persoon 2 : 90g witte, 160gr bruine, 150gr zwarte\n", + " * persoon 3 : 200g witte, 50gr bruine, 100gr zwarte\n", + " * persoon 4 : 120g witte, 310gr zwarte\n", + "De volgende prijzen worden gehanteerd :\n", + "* witte chocolade : 2.98 euro / 100g\n", + "* bruine chocolade : 1.99 euro /100g\n", + "* zwarte chocolade : 3.90 euro /100g\n", + "\n", + "Bereken via matrix operaties in numpy hoeveel euro elk van hen zal betalen." + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[100 175 210]\n", + " [ 90 160 150]\n", + " [200 50 100]\n", + " [120 0 310]]\n", + "[[0.039 ]\n", + " [0.0199]\n", + " [0.0298]]\n", + "[[13.6405]\n", + " [11.164 ]\n", + " [11.775 ]\n", + " [13.918 ]]\n" + ] + } + ], + "source": [ + "import numpy as np\n", + "a = np.mat(((100, 175, 210), (90, 160, 150), (200,50,100), (120,0,310)))\n", + "b = np.mat((2.98/100,1.99/100,3.90/100))\n", + "b = np.rot90(b)\n", + "print(a)\n", + "print(b)\n", + "print(a*b)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Oefening 4__ Oplossen van een stelsel van lineaire vergelijkingen adhv matrices\n", + "\n", + "Gegeven volgend stelsel : \n", + "\n", + "\\begin{equation*}\n", + "\\begin{array}{cc}\n", + " y &=& 2x \\\\\n", + " y &=& -x + 3\n", + "\\end{array}\n", + "\\end{equation*}\n", + "\n", + "\n", + "Zoek enerzijds een oplossing via de formule $\\bf{x} = \\bf{A}^{-1} \\bf{b}$ (zie slides : zoek eerst $\\bf{A}, \\bf{A}^{-1}$ en $\\bf{b}$)\n", + "\n", + "Zoek anderzijds een oplossing door de twee rechten te plotten en visueel het snijpunt te zoeken. " + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[1. 2.]]\n" + ] + } + ], + "source": [ + "from numpy.linalg import inv\n", + "\n", + "def a(x):\n", + " for i in range(x):\n", + " yield 2*i\n", + "\n", + "def b(x):\n", + " for i in range(x):\n", + " yield -i+3\n", + "\n", + "test = 5\n", + "plt.plot(range(test), list(a(test)))\n", + "plt.plot(range(test), list(b(test)))\n", + "plt.show()\n", + "\n", + "c = np.mat(((-2,1),(1,1)))\n", + "d = np.mat((0,3))\n", + "e = inv(c)\n", + "print(d*e)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Oefening 5__ Lineaire transformaties en random punten\n", + "De $numpy.random$ module voorziet in het genereren van random waarden (voor verschillende probabiliteitsdistributies, bvb de normale verdeling). Genereer een (10x2) matrix met 10 random x en 10 random y waarden volgens een normale verdeling in het interval $[0,1]$. Transformeer vervolgens deze 10 random coordinaten naar 10 nieuwe coordinaten via volgende lineaire transformatie :\n", + "\\begin{equation*}\n", + "\\bf{A} = \n", + "\\begin{bmatrix}\n", + "-1 & 0 \\\\\n", + "0 & 1\n", + "\\end{bmatrix}\n", + "\\end{equation*}\n", + "Bereken eerst de determinant van de matrix. (dit geeft je alvast informatie over het type transformatie.)\n", + "Plot de originele 10 random coördinaten (verbindt ze via een lijn) en doe hetzelfde met de getransformeerde coördinaten. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__Oefening 6__: Kwadratische functies of parabolen\n", + "\n", + "Kwadratische functies of parabolen kan je als volgt definiëren :\n", + "\\begin{equation}\n", + "y = a (x - \\alpha)^2 + \\beta\n", + "\\end{equation}\n", + "\n", + "M.a.w. de parabool is volledig gedefinieerd als je de waarden $a, \\alpha$ en $\\beta$ kent. Van een parabool kan je de top (of het dal) berekenen, de nulpunten (dit zijn de snijpunten met de x-as, er zijn er 2,0 of geen) en de snijpunten met de y-as. Dit doe je als volgt :\n", + "\n", + "* de top bevindt zich op de coördinaten : $(\\alpha,\\beta)$\n", + "\n", + "* de nulpunten hebben als coördinaten : $((- of +) \\sqrt(\\frac{- \\beta}{a}) + \\alpha, 0)$\n", + "\n", + "* snypunt met de y-as : $(0, a\\alpha^2 + \\beta)$\n", + "\n", + "1.a. Schrijf nu zelf een Python-functie $kenmerken\\_parabool(a, alpha, beta)$ die 3 resultaten teruggeeft : de top, de nulpunten en het snijpunt van de y-as\n", + "\n", + "1.b Schrijf een functie $waardentabel\\_parabool(a, alpha,beta)$ die een 2dim array berekent met in de eerste rij de x-waarden en als tweede rij de y-waarden van de parabool. De middenste waarde van de tabel is de top, neem nog 3 x-waarden kleiner en 3 x-waarden groter dan de top mee op in de waardentabel. In totaal heb je dus een 2dim array van 7 op 2.\n", + "\n", + "1.c Schrijf een functie $parabool(a,alpha,beta)$ die gebruik makende van de waardentabel bepaald in vorige functie een plot maakt van de parabool. \n", + "Plaats de vergelijking zelf in de grafiektitel.\n", + "\n", + "Test je methodes uit met volgende parabolen : \n", + "* $y = 2(x - 1)^2 - 12$\n", + "* $y = -4(x - 1)^2 + 4$\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "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.6.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}