{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Linear algebra" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "**Vectorizing** code is the key to writing efficient numerical calculation with Python/Numpy. \n", "\n", "That means that as much as possible of a program should be formulated in terms of matrix and vector operations, like **matrix-matrix multiplication**." ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Scalar-array operations" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We can use the usual arithmetic operators to multiply, add, subtract, and divide arrays with scalar numbers." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "v1 = np.arange(0, 5)" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([0, 2, 4, 6, 8])" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 * 2" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([2, 3, 4, 5, 6])" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 + 2" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "A = np.array([[n+m*10 for n in range(5)] for m in range(5)])" ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "A * 2: \n", " [[ 0 2 4 6 8]\n", " [20 22 24 26 28]\n", " [40 42 44 46 48]\n", " [60 62 64 66 68]\n", " [80 82 84 86 88]]\n", "A + 2: \n", " [[ 2 3 4 5 6]\n", " [12 13 14 15 16]\n", " [22 23 24 25 26]\n", " [32 33 34 35 36]\n", " [42 43 44 45 46]]\n" ] } ], "source": [ "print('A * 2: ', '\\n', A * 2)\n", "print('A + 2: ', '\\n', A + 2)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Element-wise array-array operations" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "When we add, subtract, multiply and divide arrays with each other, the default behaviour is **element-wise** operations:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 4, 9, 16],\n", " [ 100, 121, 144, 169, 196],\n", " [ 400, 441, 484, 529, 576],\n", " [ 900, 961, 1024, 1089, 1156],\n", " [1600, 1681, 1764, 1849, 1936]])" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * A # element-wise multiplication" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([ 0, 1, 4, 9, 16])" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v1 * v1" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "If we multiply arrays with compatible shapes, we get an element-wise multiplication of each row:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "((5, 5), (5,))" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A.shape, v1.shape" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 4, 9, 16],\n", " [ 0, 11, 24, 39, 56],\n", " [ 0, 21, 44, 69, 96],\n", " [ 0, 31, 64, 99, 136],\n", " [ 0, 41, 84, 129, 176]])" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A * v1" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Matrix algebra" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "What about **matrix mutiplication**? \n", "\n", "There are two ways. \n", "\n", "We can either use the `np.dot` function, which applies a **matrix-matrix**, **matrix-vector**, or **inner vector multiplication** to its two arguments: " ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 300, 310, 320, 330, 340],\n", " [1300, 1360, 1420, 1480, 1540],\n", " [2300, 2410, 2520, 2630, 2740],\n", " [3300, 3460, 3620, 3780, 3940],\n", " [4300, 4510, 4720, 4930, 5140]])" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.dot(A, A)" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([ 30, 130, 230, 330, 430])" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.dot(A, v1)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "30" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.dot(v1, v1)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## A *new* dedicated Infix operator for Matrix Multiplication\n", "\n", "**Python 3.5** (released on the **24th Aug.**) introduces a new binary operator to be used for matrix multiplication, called `@` . (Mnemonic: `@` is * for `mATrices`.)\n", "\n", "Some useful hints:\n", "\n", "- PEP465 Description: [https://www.python.org/dev/peps/pep-0465/#abstract]()\n", "- [Motivations](https://www.python.org/dev/peps/pep-0465/#motivation)\n", "- [Rationale for Specification Details](https://www.python.org/dev/peps/pep-0465/#rationale-for-specification-details)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### The `Matrix` Array Type" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Alternatively, we can cast the array objects to the type `matrix`. \n", "\n", "This changes the behavior of the standard arithmetic operators `+, -, *` to use matrix algebra." ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "from numpy import matrix" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "M = matrix(A)\n", "v = matrix(v1).T # make it a column vector" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[0],\n", " [1],\n", " [2],\n", " [3],\n", " [4]])" ] }, "execution_count": 39, "metadata": {}, "output_type": "execute_result" } ], "source": [ "v" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 300, 310, 320, 330, 340],\n", " [1300, 1360, 1420, 1480, 1540],\n", " [2300, 2410, 2520, 2630, 2740],\n", " [3300, 3460, 3620, 3780, 3940],\n", " [4300, 4510, 4720, 4930, 5140]])" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M * M" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 30],\n", " [130],\n", " [230],\n", " [330],\n", " [430]])" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "M * v" ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[30]])" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# inner product\n", "v.T * v" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 30],\n", " [131],\n", " [232],\n", " [333],\n", " [434]])" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# with matrix objects, standard matrix algebra applies\n", "v + M*v" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "If we try to add, subtract or multiply objects with incomplatible shapes we get an error:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "v = matrix([1,2,3,4,5,6]).T" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "ename": "NameError", "evalue": "name 'shape' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mM\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mshape\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'shape' is not defined" ] } ], "source": [ "shape(M), shape(v)" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "ename": "ValueError", "evalue": "shapes (5,5) and (6,1) not aligned: 5 (dim 1) != 6 (dim 0)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mM\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;32m/Users/valerio/anaconda/lib/python3.4/site-packages/numpy/matrixlib/defmatrix.py\u001b[0m in \u001b[0;36m__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 339\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mndarray\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlist\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 340\u001b[0m \u001b[0;31m# This promotes 1-D vectors to row vectors\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 341\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0masmatrix\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 342\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0misscalar\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0mhasattr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mother\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'__rmul__'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 343\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mN\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mother\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: shapes (5,5) and (6,1) not aligned: 5 (dim 1) != 6 (dim 0)" ] } ], "source": [ "M * v" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "See also the related functions: `inner`, `outer`, `cross`, `kron`, `tensordot`. \n", "\n", "Try for example `help(inner)`." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## Array/Matrix transformations" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Above we have used the `.T` to transpose the matrix object `v`. We could also have used the `transpose` function to accomplish the same thing. \n", "\n", "Other mathematical functions that transforms matrix objects are:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 0.+1.j, 0.+2.j],\n", " [ 0.+3.j, 0.+4.j]])" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C = matrix([[1j, 2j], [3j, 4j]])\n", "C" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 0.-1.j, 0.-2.j],\n", " [ 0.-3.j, 0.-4.j]])" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.conjugate(C)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* **Hermitian conjugate**: transpose + conjugate" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 0.-1.j, 0.-3.j],\n", " [ 0.-2.j, 0.-4.j]])" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.H" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We can extract the real and imaginary parts of complex-valued arrays using `real` and `imag`:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 0., 0.],\n", " [ 0., 0.]])" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.real(C) # same as: C.real" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 1., 2.],\n", " [ 3., 4.]])" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.imag(C) # same as: C.imag" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Or the complex argument and absolute value" ] }, { "cell_type": "code", "execution_count": 54, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 0.78539816, 1.10714872],\n", " [ 1.24904577, 1.32581766]])" ] }, "execution_count": 54, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.angle(C+1) # heads up MATLAB Users, angle is used instead of arg" ] }, { "cell_type": "code", "execution_count": 56, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function angle in module numpy.lib.function_base:\n", "\n", "angle(z, deg=0)\n", " Return the angle of the complex argument.\n", " \n", " Parameters\n", " ----------\n", " z : array_like\n", " A complex number or sequence of complex numbers.\n", " deg : bool, optional\n", " Return angle in degrees if True, radians if False (default).\n", " \n", " Returns\n", " -------\n", " angle : {ndarray, scalar}\n", " The counterclockwise angle from the positive real axis on\n", " the complex plane, with dtype as numpy.float64.\n", " \n", " See Also\n", " --------\n", " arctan2\n", " absolute\n", " \n", " \n", " \n", " Examples\n", " --------\n", " >>> np.angle([1.0, 1.0j, 1+1j]) # in radians\n", " array([ 0. , 1.57079633, 0.78539816])\n", " >>> np.angle(1+1j, deg=True) # in degrees\n", " 45.0\n", "\n" ] } ], "source": [ "help(np.angle)" ] }, { "cell_type": "code", "execution_count": 55, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 1., 2.],\n", " [ 3., 4.]])" ] }, "execution_count": 55, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.abs(C)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Matrix computations" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Inverse: `np.linalg.inv`" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 0.+2.j , 0.-1.j ],\n", " [ 0.-1.5j, 0.+0.5j]])" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linalg.inv(C) # equivalent to C.I " ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "matrix([[ 1.00000000e+00+0.j, 0.00000000e+00+0.j],\n", " [ 2.22044605e-16+0.j, 1.00000000e+00+0.j]])" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "C.I * C" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Determinant: `np.linalg.det`" ] }, { "cell_type": "code", "execution_count": 60, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "(2.0000000000000004+0j)" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linalg.det(C)" ] }, { "cell_type": "code", "execution_count": 61, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "(0.49999999999999972+0j)" ] }, "execution_count": 61, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.linalg.det(C.I)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Reshaping, resizing and stacking arrays" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The shape of an Numpy array can be modified without copying the underlaying data, which makes it a fast operation even for large arrays." ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3, 4],\n", " [10, 11, 12, 13, 14],\n", " [20, 21, 22, 23, 24],\n", " [30, 31, 32, 33, 34],\n", " [40, 41, 42, 43, 44]])" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "n, m = A.shape" ] }, { "cell_type": "code", "execution_count": 67, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 0, 1, 2, 3, 4, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,\n", " 32, 33, 34, 40, 41, 42, 43, 44]])" ] }, "execution_count": 67, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B = A.reshape((1,n*m))\n", "B" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 5, 5, 5, 5, 5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,\n", " 32, 33, 34, 40, 41, 42, 43, 44]])" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B[0,0:5] = 5 # modify the array\n", "\n", "B" ] }, { "cell_type": "code", "execution_count": 69, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 5, 5, 5, 5, 5],\n", " [10, 11, 12, 13, 14],\n", " [20, 21, 22, 23, 24],\n", " [30, 31, 32, 33, 34],\n", " [40, 41, 42, 43, 44]])" ] }, "execution_count": 69, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A # and the original variable is also changed. B is only a different view of the same data" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### Flattening" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### `np.ravel`" ] }, { "cell_type": "code", "execution_count": 98, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([1, 2, 3, 4, 5, 6])" ] }, "execution_count": 98, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a = np.array([[1, 2, 3], [4, 5, 6]])\n", "a.ravel()" ] }, { "cell_type": "code", "execution_count": 99, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 4],\n", " [2, 5],\n", " [3, 6]])" ] }, "execution_count": 99, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.T" ] }, { "cell_type": "code", "execution_count": 100, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "array([1, 4, 2, 5, 3, 6])" ] }, "execution_count": 100, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a.T.ravel()" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "We can also use the function `flatten` to make a higher-dimensional array into a vector. But this function create a copy of the data." ] }, { "cell_type": "code", "execution_count": 70, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([ 5, 5, 5, 5, 5, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,\n", " 32, 33, 34, 40, 41, 42, 43, 44])" ] }, "execution_count": 70, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B = A.flatten()\n", "\n", "B" ] }, { "cell_type": "code", "execution_count": 71, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "array([10, 10, 10, 10, 10, 10, 11, 12, 13, 14, 20, 21, 22, 23, 24, 30, 31,\n", " 32, 33, 34, 40, 41, 42, 43, 44])" ] }, "execution_count": 71, "metadata": {}, "output_type": "execute_result" } ], "source": [ "B[0:5] = 10\n", "\n", "B" ] }, { "cell_type": "code", "execution_count": 72, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[ 5, 5, 5, 5, 5],\n", " [10, 11, 12, 13, 14],\n", " [20, 21, 22, 23, 24],\n", " [30, 31, 32, 33, 34],\n", " [40, 41, 42, 43, 44]])" ] }, "execution_count": 72, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A # now A has not changed, because B's data is a copy of A's, not refering to the same data" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Adding a new dimension: `np.newaxis`" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "With `newaxis`, we can insert new dimensions in an array, for example converting a vector to a column or row matrix:" ] }, { "cell_type": "code", "execution_count": 74, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "v = np.array([1,2,3])" ] }, { "cell_type": "code", "execution_count": 75, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "(3,)" ] }, "execution_count": 75, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.shape(v)" ] }, { "cell_type": "code", "execution_count": 77, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[1],\n", " [2],\n", " [3]])" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# make a column matrix of the vector v\n", "v[:, np.newaxis]" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "(3, 1)" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# column matrix\n", "v[:,np.newaxis].shape" ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "(1, 3)" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# row matrix\n", "v[np.newaxis,:].shape" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Stacking and repeating arrays" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "Using function `repeat`, `tile`, `vstack`, `hstack`, and `concatenate` we can create larger vectors and matrices from smaller ones:" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## `np.tile` and `np.repeat`" ] }, { "cell_type": "code", "execution_count": 82, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "a = np.array([[1, 2], [3, 4]])" ] }, { "cell_type": "code", "execution_count": 83, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# repeat each element 3 times\n", "np.repeat(a, 3)" ] }, { "cell_type": "code", "execution_count": 84, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 1, 2, 1, 2],\n", " [3, 4, 3, 4, 3, 4]])" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# tile the matrix 3 times \n", "np.tile(a, 3)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## `np.concatenate`" ] }, { "cell_type": "code", "execution_count": 85, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "b = np.array([[5, 6]])" ] }, { "cell_type": "code", "execution_count": 86, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4],\n", " [5, 6]])" ] }, "execution_count": 86, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.concatenate((a, b), axis=0)" ] }, { "cell_type": "code", "execution_count": 87, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 5],\n", " [3, 4, 6]])" ] }, "execution_count": 87, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.concatenate((a, b.T), axis=1)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "## `np.hstack` and `np.vstack`" ] }, { "cell_type": "code", "execution_count": 88, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4],\n", " [5, 6]])" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.vstack((a,b))" ] }, { "cell_type": "code", "execution_count": 89, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2, 5],\n", " [3, 4, 6]])" ] }, "execution_count": 89, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.hstack((a,b.T))" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Copy and \"deep copy\"" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "To achieve high performance, assignments in Python usually do not copy the underlaying objects. \n", "\n", "This is important for example when objects are passed between functions, to avoid an excessive amount of memory copying when it is not necessary (techincal term: **pass by reference**).\n", "\n", "" ] }, { "cell_type": "code", "execution_count": 90, "metadata": { "collapsed": false, "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "array([[1, 2],\n", " [3, 4]])" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A = np.array([[1, 2], [3, 4]])\n", "\n", "A" ] }, { "cell_type": "code", "execution_count": 91, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# now B is referring to the same array data as A \n", "B = A " ] }, { "cell_type": "code", "execution_count": 92, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[10, 2],\n", " [ 3, 4]])" ] }, "execution_count": 92, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# changing B affects A\n", "B[0,0] = 10\n", "\n", "B" ] }, { "cell_type": "code", "execution_count": 93, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[10, 2],\n", " [ 3, 4]])" ] }, "execution_count": 93, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* If we want to **avoid** this behavior, so that when we get a new completely independent object `B` copied from `A`, then we need to do a so-called **deep copy** using the function `np.copy`:" ] }, { "cell_type": "code", "execution_count": 94, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "B = np.copy(A)" ] }, { "cell_type": "code", "execution_count": 95, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[-5, 2],\n", " [ 3, 4]])" ] }, "execution_count": 95, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# now, if we modify B, A is not affected\n", "B[0,0] = -5\n", "\n", "B" ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "collapsed": false, "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "array([[10, 2],\n", " [ 3, 4]])" ] }, "execution_count": 96, "metadata": {}, "output_type": "execute_result" } ], "source": [ "A" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Exercise: Shape manipulations" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "* Look at the docstring for `reshape`, especially the notes section which\n", "has some more information about copies and views.\n", "\n", "* Use `flatten` as an alternative to `ravel`. What is the difference?\n", "(Hint: check which one returns a view and which a copy)\n", "\n", "* Experiment with `transpose` for dimension shuffling." ] } ], "metadata": { "celltoolbar": "Slideshow", "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.5.1" } }, "nbformat": 4, "nbformat_minor": 0 }