{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Numpy - multidimensional data arrays\n", "## Author: Steven Christe\n", "\n", "Numpy is the fundamental library for scientific computing in Python. It contains list-like objects that work like arrays, matrices, and data tables. It also provides linear algebra, Fourier transforms, random number generation, and tools for integrating C/C++ and Fortran code.\n", "\n", "Python was never designed originally for scientific computing, and contains many high-level abstractions necessary to enable its enormously flexible object-oriented interface. In Python, storing most integers requires more than just 4-8 bytes. It also requires at least a couple pointers per-integer. Performing a calculation on two numbers requires one or two bytecode operations, each of which can take dozens of CPU instructions for each pass through the Python eval loop. And when it comes to looping and index operations of Python lists the situation is even worst. NumPy provides efficient objects for dealing with arrays of numbers and overloads operators so you don't have to ever (hopefully) use loops!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This ipython notebook file can be found at\n", "\n", "* [ipython notebook file](https://raw.githubusercontent.com/ehsteve/ipython-notebooks/master/RHESSI%20Workshope%2013%20-%20Intro%20to%20NumPy%20&%20SciPy.ipynb)\n", "\n", "or can be viewed (if you don't have ipython installed) here\n", "\n", "* [ipython notebook viewer](http://nbviewer.ipython.org/urls/raw.githubusercontent.com/ehsteve/ipython-notebooks/master/RHESSI%20Workshope%2013%20-%20Intro%20to%20NumPy%20&%20SciPy.ipynb?create=1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is heavily cribbed from J.R. Johansson (robert@riken.jp) http://dml.riken.jp/~rob/\n", "\n", "The full version of the original talk is available at [http://github.com/jrjohansson/scientific-python-lectures](http://github.com/jrjohansson/scientific-python-lectures)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "%pylab inline" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Populating the interactive namespace from numpy and matplotlib\n" ] }, { "output_type": "stream", "stream": "stderr", "text": [ "WARNING: pylab import has clobbered these variables: ['indices']\n", "`%pylab --no-import-all` prevents importing * from pylab and numpy\n" ] } ], "prompt_number": 158 }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 159 }, { "cell_type": "code", "collapsed": false, "input": [ "import sys # only need to get python version\n", "print(\"Python version: \" + sys.version)\n", "print(\"Numpy version: \" + np.__version__)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Python version: 2.7.6 |Anaconda 1.8.0 (x86_64)| (default, Jan 10 2014, 11:23:15) \n", "[GCC 4.0.1 (Apple Inc. build 5493)]\n", "Numpy version: 1.8.1\n" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the `numpy` package the terminology used for vectors, matrices and higher-dimensional data sets is *array*. \n", "\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Creating `numpy` arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are a number of ways to initialize new numpy arrays, for example from\n", "\n", "* a Python list or tuples\n", "* using functions that are dedicated to generating numpy arrays, such as `arange`, `linspace`, etc.\n", "* reading data from files" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "From lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example, to create new vector and matrix arrays from Python lists we can use the `numpy.array` function." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# a vector: the argument to the array function is a Python list\n", "v = np.array([1,2,3,4])\n", "\n", "v" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 3, "text": [ "array([1, 2, 3, 4])" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "# a matrix: the argument to the array function is a nested Python list\n", "M = np.array([[1, 6], [3, 4]])\n", "\n", "M" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 148, "text": [ "array([[1, 6],\n", " [3, 4]])" ] } ], "prompt_number": 148 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `v` and `M` objects are both of the type `ndarray` that the `numpy` module provides." ] }, { "cell_type": "code", "collapsed": false, "input": [ "type(v), type(M)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 149, "text": [ "(numpy.ndarray, numpy.ndarray)" ] } ], "prompt_number": 149 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The difference between the `v` and `M` arrays is only their shapes. We can get information about the shape of an array by using the `ndarray.shape` property." ] }, { "cell_type": "code", "collapsed": false, "input": [ "v.shape" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 150, "text": [ "(4,)" ] } ], "prompt_number": 150 }, { "cell_type": "code", "collapsed": false, "input": [ "M.shape" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 7, "text": [ "(2, 2)" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The number of elements in the array is available through the `ndarray.size` property:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "M.size" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 8, "text": [ "4" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Equivalently, we could use the function `numpy.shape` and `numpy.size`" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.shape(M)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 9, "text": [ "(2, 2)" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "np.size(M)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 10, "text": [ "4" ] } ], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Features of a `numpy.ndarray` \n", "\n", "* Numpy arrays are **statically typed** and **homogeneous**. The type of the elements is determined when array is created.\n", "* Numpy arrays are memory efficient.\n", "* Because of the static typing, fast implementation of mathematical functions such as multiplication and addition of `numpy` arrays can be implemented in a compiled language (C and Fortran is used).\n", "\n", "Using the `dtype` (data type) property of an `ndarray`, we can see what type the data of an array has:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "M.dtype" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 11, "text": [ "dtype('int64')" ] } ], "prompt_number": 11 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We get an error if we try to assign a value of the wrong type to an element in a numpy array:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we want, we can explicitly define the type of the array data when we create it, using the `dtype` keyword argument: " ] }, { "cell_type": "code", "collapsed": false, "input": [ "M = np.array([[1, 2], [3, 4]], dtype=np.float16)\n", "\n", "M" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 12, "text": [ "array([[ 1., 2.],\n", " [ 3., 4.]], dtype=float16)" ] } ], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Common type that can be used with `dtype` are: `int`, `float`, `complex`, `bool`, `object`, etc." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Array-generating functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For larger arrays it is inpractical to initialize the data manually, using explicit python lists. Instead we can use one of the many functions in `numpy` that generates arrays of different forms. Some of the more common are:" ] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "arange" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# create a range\n", "\n", "x = np.arange(0, 10, 1) # arguments: start, stop, step\n", "\n", "x" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 13, "text": [ "array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])" ] } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": false, "input": [ "x = np.arange(-1, 1, 0.1)\n", "\n", "x" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 14, "text": [ "array([ -1.00000000e+00, -9.00000000e-01, -8.00000000e-01,\n", " -7.00000000e-01, -6.00000000e-01, -5.00000000e-01,\n", " -4.00000000e-01, -3.00000000e-01, -2.00000000e-01,\n", " -1.00000000e-01, -2.22044605e-16, 1.00000000e-01,\n", " 2.00000000e-01, 3.00000000e-01, 4.00000000e-01,\n", " 5.00000000e-01, 6.00000000e-01, 7.00000000e-01,\n", " 8.00000000e-01, 9.00000000e-01])" ] } ], "prompt_number": 14 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "linspace and logspace" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# using linspace, both end points ARE included\n", "np.linspace(0, 10, 25)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 152, "text": [ "array([ 0. , 0.41666667, 0.83333333, 1.25 ,\n", " 1.66666667, 2.08333333, 2.5 , 2.91666667,\n", " 3.33333333, 3.75 , 4.16666667, 4.58333333,\n", " 5. , 5.41666667, 5.83333333, 6.25 ,\n", " 6.66666667, 7.08333333, 7.5 , 7.91666667,\n", " 8.33333333, 8.75 , 9.16666667, 9.58333333, 10. ])" ] } ], "prompt_number": 152 }, { "cell_type": "code", "collapsed": false, "input": [ "np.logspace(0, 10, 10, base=e)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 16, "text": [ "array([ 1.00000000e+00, 3.03773178e+00, 9.22781435e+00,\n", " 2.80316249e+01, 8.51525577e+01, 2.58670631e+02,\n", " 7.85771994e+02, 2.38696456e+03, 7.25095809e+03,\n", " 2.20264658e+04])" ] } ], "prompt_number": 16 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "mgrid" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x, y = np.mgrid[0:5, 0:5] # similar to meshgrid in MATLAB" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "x" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ "array([[0, 0, 0, 0, 0],\n", " [1, 1, 1, 1, 1],\n", " [2, 2, 2, 2, 2],\n", " [3, 3, 3, 3, 3],\n", " [4, 4, 4, 4, 4]])" ] } ], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "y" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 19, "text": [ "array([[0, 1, 2, 3, 4],\n", " [0, 1, 2, 3, 4],\n", " [0, 1, 2, 3, 4],\n", " [0, 1, 2, 3, 4],\n", " [0, 1, 2, 3, 4]])" ] } ], "prompt_number": 19 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "random data" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from numpy import random" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "# uniform random numbers in [0,1]\n", "random.rand(5,5)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 21, "text": [ "array([[ 0.32846187, 0.42213273, 0.01968231, 0.21261055, 0.51482732],\n", " [ 0.08183575, 0.00824206, 0.62834203, 0.77968281, 0.126293 ],\n", " [ 0.38743163, 0.86545303, 0.40312758, 0.8053914 , 0.48047428],\n", " [ 0.61395831, 0.89044911, 0.14621425, 0.48195724, 0.38045612],\n", " [ 0.20086805, 0.27765159, 0.08753675, 0.18159165, 0.64932571]])" ] } ], "prompt_number": 21 }, { "cell_type": "code", "collapsed": false, "input": [ "# standard normal distributed random numbers\n", "random.randn(5,5)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 22, "text": [ "array([[-0.78404982, -0.57134026, 1.49107161, -1.26857542, 0.44456653],\n", " [-0.02629558, 0.08901156, -1.08758579, 0.22911653, -1.98229464],\n", " [ 0.33490693, 0.65502718, 0.23791072, -0.22042591, -0.01485002],\n", " [ 1.49117271, -0.76377386, 0.54285327, -0.78657823, 1.72420386],\n", " [ 1.77250365, -1.02862661, 0.07318933, -0.06165841, -1.93811428]])" ] } ], "prompt_number": 22 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "zeros and ones" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.zeros((3,3))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 23, "text": [ "array([[ 0., 0., 0.],\n", " [ 0., 0., 0.],\n", " [ 0., 0., 0.]])" ] } ], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "np.ones((3,3))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 24, "text": [ "array([[ 1., 1., 1.],\n", " [ 1., 1., 1.],\n", " [ 1., 1., 1.]])" ] } ], "prompt_number": 24 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "More properties of the numpy arrays" ] }, { "cell_type": "code", "collapsed": false, "input": [ "M.itemsize # bytes per element" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 25, "text": [ "2" ] } ], "prompt_number": 25 }, { "cell_type": "code", "collapsed": false, "input": [ "M.nbytes # number of bytes" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 26, "text": [ "8" ] } ], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": [ "M.ndim # number of dimensions" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 27, "text": [ "2" ] } ], "prompt_number": 27 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Manipulating arrays" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Indexing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can index elements in an array using the square bracket and indices:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# v is a vector, and has only one dimension, taking one index\n", "v[0]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 154, "text": [ "1" ] } ], "prompt_number": 154 }, { "cell_type": "code", "collapsed": false, "input": [ "# M is a matrix, or a 2 dimensional array, taking two indices \n", "M[1,1]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 29, "text": [ "4.0" ] } ], "prompt_number": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same thing can be achieved with using `:` instead of an index: " ] }, { "cell_type": "code", "collapsed": false, "input": [ "M[1,:] # row 1" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 30, "text": [ "array([ 3., 4.], dtype=float16)" ] } ], "prompt_number": 30 }, { "cell_type": "code", "collapsed": false, "input": [ "M[:,1] # column 1" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 31, "text": [ "array([ 2., 4.], dtype=float16)" ] } ], "prompt_number": 31 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can assign new values to elements in an array using indexing:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "M[0,0] = 1" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 32 }, { "cell_type": "code", "collapsed": false, "input": [ "M" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 33, "text": [ "array([[ 1., 2.],\n", " [ 3., 4.]], dtype=float16)" ] } ], "prompt_number": 33 }, { "cell_type": "code", "collapsed": false, "input": [ "# also works for rows and columns\n", "M[1,:] = 0\n", "M[:,1] = -1" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "M" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 35, "text": [ "array([[ 1., -1.],\n", " [ 0., -1.]], dtype=float16)" ] } ], "prompt_number": 35 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Index slicing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Index slicing is the technical name for the syntax `M[lower:upper:step]` to extract part of an array:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.array([1,2,3,4,5])\n", "A" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 36, "text": [ "array([1, 2, 3, 4, 5])" ] } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": [ "A[1:3]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 37, "text": [ "array([2, 3])" ] } ], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Array slices are *mutable*: if they are assigned a new value the original array from which the slice was extracted is modified:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A[1:3] = [-2,-3]\n", "\n", "A" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 38, "text": [ "array([ 1, -2, -3, 4, 5])" ] } ], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can omit any of the three parameters in `M[lower:upper:step]`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A[::] # lower, upper, step all take the default values" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 39, "text": [ "array([ 1, -2, -3, 4, 5])" ] } ], "prompt_number": 39 }, { "cell_type": "code", "collapsed": false, "input": [ "A[::2] # step is 2, lower and upper defaults to the beginning and end of the array" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 40, "text": [ "array([ 1, -3, 5])" ] } ], "prompt_number": 40 }, { "cell_type": "code", "collapsed": false, "input": [ "A[:3] # first three elements" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 41, "text": [ "array([ 1, -2, -3])" ] } ], "prompt_number": 41 }, { "cell_type": "code", "collapsed": false, "input": [ "A[3:] # elements from index 3" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 42, "text": [ "array([4, 5])" ] } ], "prompt_number": 42 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Negative indices counts from the end of the array (positive index from the begining):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.array([1,2,3,4,5])" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 43 }, { "cell_type": "code", "collapsed": false, "input": [ "A[-1] # the last element in the array" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 44, "text": [ "5" ] } ], "prompt_number": 44 }, { "cell_type": "code", "collapsed": false, "input": [ "A[-3:] # the last three elements" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 45, "text": [ "array([3, 4, 5])" ] } ], "prompt_number": 45 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Index slicing works exactly the same way for multidimensional arrays:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.array([[n+m*10 for n in range(5)] for m in range(5)])\n", "\n", "A" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 46, "text": [ "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]])" ] } ], "prompt_number": 46 }, { "cell_type": "code", "collapsed": false, "input": [ "# a block from the original array\n", "A[1:4, 1:4]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 47, "text": [ "array([[11, 12, 13],\n", " [21, 22, 23],\n", " [31, 32, 33]])" ] } ], "prompt_number": 47 }, { "cell_type": "code", "collapsed": false, "input": [ "# strides\n", "A[::2, ::2]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 48, "text": [ "array([[ 0, 2, 4],\n", " [20, 22, 24],\n", " [40, 42, 44]])" ] } ], "prompt_number": 48 }, { "cell_type": "code", "collapsed": false, "input": [ "A[1]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 157, "text": [ "array([3, 4])" ] } ], "prompt_number": 157 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Fancy indexing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Fancy indexing is the name for when an array or list is used in-place of an index: " ] }, { "cell_type": "code", "collapsed": false, "input": [ "row_indices = [1, 2, 3]\n", "A[row_indices]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 49, "text": [ "array([[10, 11, 12, 13, 14],\n", " [20, 21, 22, 23, 24],\n", " [30, 31, 32, 33, 34]])" ] } ], "prompt_number": 49 }, { "cell_type": "code", "collapsed": false, "input": [ "col_indices = [1, 2, -1] # remember, index -1 means the last element\n", "A[row_indices, col_indices]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 50, "text": [ "array([11, 22, 34])" ] } ], "prompt_number": 50 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also index masks: If the index mask is an Numpy array of with data type `bool`, then an element is selected (True) or not (False) depending on the value of the index mask at the position each element: " ] }, { "cell_type": "code", "collapsed": false, "input": [ "B = array([n for n in range(5)])\n", "B" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 51, "text": [ "array([0, 1, 2, 3, 4])" ] } ], "prompt_number": 51 }, { "cell_type": "code", "collapsed": false, "input": [ "row_mask = array([True, False, True, False, False])\n", "B[row_mask]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 52, "text": [ "array([0, 2])" ] } ], "prompt_number": 52 }, { "cell_type": "code", "collapsed": false, "input": [ "# same thing\n", "row_mask = array([1,0,1,0,0], dtype=bool)\n", "B[row_mask]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 53, "text": [ "array([0, 2])" ] } ], "prompt_number": 53 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This feature is very useful to conditionally select elements from an array, using for example comparison operators:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x = np.arange(0, 10, 0.5)\n", "x" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 54, "text": [ "array([ 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. ,\n", " 5.5, 6. , 6.5, 7. , 7.5, 8. , 8.5, 9. , 9.5])" ] } ], "prompt_number": 54 }, { "cell_type": "code", "collapsed": false, "input": [ "mask = (5 < x) * (x < 7.5)\n", "\n", "mask" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 55, "text": [ "array([False, False, False, False, False, False, False, False, False,\n", " False, False, True, True, True, True, False, False, False,\n", " False, False], dtype=bool)" ] } ], "prompt_number": 55 }, { "cell_type": "code", "collapsed": false, "input": [ "x[mask]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 56, "text": [ "array([ 5.5, 6. , 6.5, 7. ])" ] } ], "prompt_number": 56 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Functions for extracting data from arrays and creating arrays" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "where" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The index mask can be converted to position index using the `where` function" ] }, { "cell_type": "code", "collapsed": false, "input": [ "indices = np.where(mask)\n", "\n", "indices" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 57, "text": [ "(array([11, 12, 13, 14]),)" ] } ], "prompt_number": 57 }, { "cell_type": "code", "collapsed": false, "input": [ "x[indices] # this indexing is equivalent to the fancy indexing x[mask]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 58, "text": [ "array([ 5.5, 6. , 6.5, 7. ])" ] } ], "prompt_number": 58 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "diag" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the diag function we can also extract the diagonal and subdiagonals of an array:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.diag(A)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 59, "text": [ "array([ 0, 11, 22, 33, 44])" ] } ], "prompt_number": 59 }, { "cell_type": "code", "collapsed": false, "input": [ "np.diag(A, -1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 60, "text": [ "array([10, 21, 32, 43])" ] } ], "prompt_number": 60 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "take" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `take` function is similar to fancy indexing described above:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "v2 = np.arange(-3,3)\n", "v2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 61, "text": [ "array([-3, -2, -1, 0, 1, 2])" ] } ], "prompt_number": 61 }, { "cell_type": "code", "collapsed": false, "input": [ "row_indices = [1, 3, 5]\n", "v2[row_indices] # fancy indexing" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 62, "text": [ "array([-2, 0, 2])" ] } ], "prompt_number": 62 }, { "cell_type": "code", "collapsed": false, "input": [ "v2.take(row_indices)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 63, "text": [ "array([-2, 0, 2])" ] } ], "prompt_number": 63 }, { "cell_type": "markdown", "metadata": {}, "source": [ "But `take` also works on lists and other objects:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.take([-3, -2, -1, 0, 1, 2], row_indices)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 64, "text": [ "array([-2, 0, 2])" ] } ], "prompt_number": 64 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "choose" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Constructs and array by picking elements form several arrays:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "which = [1, 0, 1, 0]\n", "choices = [[-2,-2,-2,-2], [5,5,5,5]]\n", "\n", "np.choose(which, choices)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 65, "text": [ "array([ 5, -2, 5, -2])" ] } ], "prompt_number": 65 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Linear algebra" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vectorizing code is the key to writing efficient numerical calculation with Python/Numpy. 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": "heading", "level": 3, "metadata": {}, "source": [ "Scalar-array operations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use the usual arithmetic operators to multiply, add, subtract, and divide arrays with scalar numbers." ] }, { "cell_type": "code", "collapsed": false, "input": [ "v1 = np.arange(0, 5)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 66 }, { "cell_type": "code", "collapsed": false, "input": [ "v1 * 2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 67, "text": [ "array([0, 2, 4, 6, 8])" ] } ], "prompt_number": 67 }, { "cell_type": "code", "collapsed": false, "input": [ "v1 + 2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 68, "text": [ "array([2, 3, 4, 5, 6])" ] } ], "prompt_number": 68 }, { "cell_type": "code", "collapsed": false, "input": [ "A * 2, A + 2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 69, "text": [ "(array([[ 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", " array([[ 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]]))" ] } ], "prompt_number": 69 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Element-wise array-array operations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When we add, subtract, multiply and divide arrays with each other, the default behaviour is **element-wise** operations:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A * A # element-wise multiplication" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 70, "text": [ "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]])" ] } ], "prompt_number": 70 }, { "cell_type": "code", "collapsed": false, "input": [ "v1 * v1" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 71, "text": [ "array([ 0, 1, 4, 9, 16])" ] } ], "prompt_number": 71 }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we multiply arrays with compatible shapes, we get an element-wise multiplication of each row:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A.shape, v1.shape" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 72, "text": [ "((5, 5), (5,))" ] } ], "prompt_number": 72 }, { "cell_type": "code", "collapsed": false, "input": [ "A * v1" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 73, "text": [ "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]])" ] } ], "prompt_number": 73 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Matrix algebra" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What about matrix mutiplication? There are two ways. We can either use the `dot` function, which applies a matrix-matrix, matrix-vector, or inner vector multiplication to its two arguments: " ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.dot(A, A)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 74, "text": [ "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]])" ] } ], "prompt_number": 74 }, { "cell_type": "code", "collapsed": false, "input": [ "np.dot(A, v1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 75, "text": [ "array([ 30, 130, 230, 330, 430])" ] } ], "prompt_number": 75 }, { "cell_type": "code", "collapsed": false, "input": [ "np.dot(v1, v1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 76, "text": [ "30" ] } ], "prompt_number": 76 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, we can cast the array objects to the type `matrix`. This changes the behavior of the standard arithmetic operators `+, -, *` to use matrix algebra." ] }, { "cell_type": "code", "collapsed": false, "input": [ "M = np.matrix(A)\n", "v = np.matrix(v1).T # make it a column vector" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 77 }, { "cell_type": "code", "collapsed": false, "input": [ "v" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 78, "text": [ "matrix([[0],\n", " [1],\n", " [2],\n", " [3],\n", " [4]])" ] } ], "prompt_number": 78 }, { "cell_type": "code", "collapsed": false, "input": [ "M * M" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 79, "text": [ "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]])" ] } ], "prompt_number": 79 }, { "cell_type": "code", "collapsed": false, "input": [ "M * v" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 80, "text": [ "matrix([[ 30],\n", " [130],\n", " [230],\n", " [330],\n", " [430]])" ] } ], "prompt_number": 80 }, { "cell_type": "code", "collapsed": false, "input": [ "# inner product\n", "v.T * v" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 81, "text": [ "matrix([[30]])" ] } ], "prompt_number": 81 }, { "cell_type": "code", "collapsed": false, "input": [ "# with matrix objects, standard matrix algebra applies\n", "v + M*v" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 82, "text": [ "matrix([[ 30],\n", " [131],\n", " [232],\n", " [333],\n", " [434]])" ] } ], "prompt_number": 82 }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we try to add, subtract or multiply objects with incomplatible shapes we get an error:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "v = np.matrix([1,2,3,4,5,6]).T" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 83 }, { "cell_type": "code", "collapsed": false, "input": [ "shape(M), shape(v)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 84, "text": [ "((5, 5), (6, 1))" ] } ], "prompt_number": 84 }, { "cell_type": "code", "collapsed": false, "input": [ "M * v" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "objects are not aligned", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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/schriste/anaconda/lib/python2.7/site-packages/numpy/matrixlib/defmatrix.pyc\u001b[0m in \u001b[0;36m__mul__\u001b[0;34m(self, other)\u001b[0m\n\u001b[1;32m 328\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 329\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--> 330\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 331\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 332\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: objects are not aligned" ] } ], "prompt_number": 85 }, { "cell_type": "markdown", "metadata": {}, "source": [ "See also the related functions: `inner`, `outer`, `cross`, `kron`, `tensordot`. Try for example `help(kron)`." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Array/Matrix transformations" ] }, { "cell_type": "markdown", "metadata": {}, "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", "collapsed": false, "input": [ "C = np.matrix([[1j, 2j], [3j, 4j]])\n", "C" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "np.conjugate(C)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mconjugate\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 86 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Hermitian conjugate: transpose + conjugate" ] }, { "cell_type": "code", "collapsed": false, "input": [ "C.H" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mC\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mH\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 87 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can extract the real and imaginary parts of complex-valued arrays using `real` and `imag`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.real(C) # same as: C.real" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mreal\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# same as: C.real\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 88 }, { "cell_type": "code", "collapsed": false, "input": [ "np.imag(C) # same as: C.imag" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mimag\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# same as: C.imag\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 89 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or the complex argument and absolute value" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.angle(C+1) # heads up MATLAB Users, angle is used instead of arg" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mangle\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# heads up MATLAB Users, angle is used instead of arg\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 90 }, { "cell_type": "code", "collapsed": false, "input": [ "np.abs(C)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mabs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 91 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Matrix computations" ] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Inverse" ] }, { "cell_type": "code", "collapsed": false, "input": [ "inv(C) # equivalent to C.I " ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0minv\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mC\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# equivalent to C.I\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 92 }, { "cell_type": "code", "collapsed": false, "input": [ "C.I * C" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'C' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mC\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mI\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mC\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'C' is not defined" ] } ], "prompt_number": 93 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Determinant" ] }, { "cell_type": "code", "collapsed": false, "input": [ "det(C)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "det(C.I)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "sum, prod, and trace" ] }, { "cell_type": "code", "collapsed": false, "input": [ "d = arange(0, 10)\n", "d" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# sum up all elements\n", "sum(d)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# product of all elements\n", "prod(d+1)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'd' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[1;32m 1\u001b[0m \u001b[0;31m# product of all elements\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mprod\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'd' is not defined" ] } ], "prompt_number": 94 }, { "cell_type": "code", "collapsed": false, "input": [ "# cummulative sum\n", "cumsum(d)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'd' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[1;32m 1\u001b[0m \u001b[0;31m# cummulative sum\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mcumsum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'd' is not defined" ] } ], "prompt_number": 95 }, { "cell_type": "code", "collapsed": false, "input": [ "# cummulative product\n", "cumprod(d+1)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'd' is not defined", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[1;32m 1\u001b[0m \u001b[0;31m# cummulative product\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mcumprod\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0md\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mNameError\u001b[0m: name 'd' is not defined" ] } ], "prompt_number": 96 }, { "cell_type": "code", "collapsed": false, "input": [ "# same as: diag(A).sum()\n", "trace(A)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 97, "text": [ "110" ] } ], "prompt_number": 97 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Calculations with higher-dimensional data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When functions such as `min`, `max`, etc., is applied to a multidimensional arrays, it is sometimes useful to apply the calculation to the entire array, and sometimes only on a row or column basis. Using the `axis` argument we can specify how these functions should behave: " ] }, { "cell_type": "code", "collapsed": false, "input": [ "m = rand(3,3)\n", "m" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 98, "text": [ "array([[ 0.45974672, 0.90724345, 0.23833268],\n", " [ 0.90236963, 0.51838115, 0.64488138],\n", " [ 0.49125775, 0.50524105, 0.3813743 ]])" ] } ], "prompt_number": 98 }, { "cell_type": "code", "collapsed": false, "input": [ "# global max\n", "m.max()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 99, "text": [ "0.90724344539482737" ] } ], "prompt_number": 99 }, { "cell_type": "code", "collapsed": false, "input": [ "# max in each column\n", "m.max(axis=0)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 100, "text": [ "array([ 0.90236963, 0.90724345, 0.64488138])" ] } ], "prompt_number": 100 }, { "cell_type": "code", "collapsed": false, "input": [ "# max in each row\n", "m.max(axis=1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 101, "text": [ "array([ 0.90724345, 0.90236963, 0.50524105])" ] } ], "prompt_number": 101 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Many other functions and methods in the `array` and `matrix` classes accept the same (optional) `axis` keyword argument." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Reshaping, resizing and stacking arrays" ] }, { "cell_type": "markdown", "metadata": {}, "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", "collapsed": false, "input": [ "A" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 102, "text": [ "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]])" ] } ], "prompt_number": 102 }, { "cell_type": "code", "collapsed": false, "input": [ "n, m = A.shape" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 103 }, { "cell_type": "code", "collapsed": false, "input": [ "B = A.reshape((1,n*m))\n", "B" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 104, "text": [ "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]])" ] } ], "prompt_number": 104 }, { "cell_type": "code", "collapsed": false, "input": [ "B[0,0:5] = 5 # modify the array\n", "\n", "B" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 105, "text": [ "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]])" ] } ], "prompt_number": 105 }, { "cell_type": "code", "collapsed": false, "input": [ "A # and the original variable is also changed. B is only a different view of the same data" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 106, "text": [ "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]])" ] } ], "prompt_number": 106 }, { "cell_type": "markdown", "metadata": {}, "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", "collapsed": false, "input": [ "B = A.flatten()\n", "\n", "B" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 107, "text": [ "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])" ] } ], "prompt_number": 107 }, { "cell_type": "code", "collapsed": false, "input": [ "B[0:5] = 10\n", "\n", "B" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 108, "text": [ "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])" ] } ], "prompt_number": 108 }, { "cell_type": "code", "collapsed": false, "input": [ "A # now A has not changed, because B's data is a copy of A's, not refering to the same data" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 109, "text": [ "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]])" ] } ], "prompt_number": 109 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Adding a new dimension: newaxis" ] }, { "cell_type": "markdown", "metadata": {}, "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", "collapsed": false, "input": [ "v = np.array([1,2,3])" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 110 }, { "cell_type": "code", "collapsed": false, "input": [ "np.shape(v)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 111, "text": [ "(3,)" ] } ], "prompt_number": 111 }, { "cell_type": "code", "collapsed": false, "input": [ "# make a column matrix of the vector v\n", "v[:, newaxis]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 112, "text": [ "array([[1],\n", " [2],\n", " [3]])" ] } ], "prompt_number": 112 }, { "cell_type": "code", "collapsed": false, "input": [ "# column matrix\n", "v[:,newaxis].shape" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 113, "text": [ "(3, 1)" ] } ], "prompt_number": 113 }, { "cell_type": "code", "collapsed": false, "input": [ "# row matrix\n", "v[newaxis,:].shape" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 114, "text": [ "(1, 3)" ] } ], "prompt_number": 114 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Stacking and repeating arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using function `repeat`, `tile`, `vstack`, `hstack`, and `concatenate` we can create larger vectors and matrices from smaller ones:" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "tile and repeat" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.array([[1, 2], [3, 4]])" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 115 }, { "cell_type": "code", "collapsed": false, "input": [ "# repeat each element 3 times\n", "np.repeat(a, 3)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 116, "text": [ "array([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4])" ] } ], "prompt_number": 116 }, { "cell_type": "code", "collapsed": false, "input": [ "# tile the matrix 3 times \n", "np.tile(a, 3)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 117, "text": [ "array([[1, 2, 1, 2, 1, 2],\n", " [3, 4, 3, 4, 3, 4]])" ] } ], "prompt_number": 117 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "concatenate" ] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.array([[5, 6]])" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 118 }, { "cell_type": "code", "collapsed": false, "input": [ "np.concatenate((a, b), axis=0)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 119, "text": [ "array([[1, 2],\n", " [3, 4],\n", " [5, 6]])" ] } ], "prompt_number": 119 }, { "cell_type": "code", "collapsed": false, "input": [ "np.concatenate((a, b.T), axis=1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 120, "text": [ "array([[1, 2, 5],\n", " [3, 4, 6]])" ] } ], "prompt_number": 120 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "hstack and vstack" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.vstack((a,b))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 121, "text": [ "array([[1, 2],\n", " [3, 4],\n", " [5, 6]])" ] } ], "prompt_number": 121 }, { "cell_type": "code", "collapsed": false, "input": [ "np.hstack((a,b.T))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 122, "text": [ "array([[1, 2, 5],\n", " [3, 4, 6]])" ] } ], "prompt_number": 122 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Copy and \"deep copy\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To achieve high performance, assignments in Python usually do not copy the underlaying objects. 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). " ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.array([[1, 2], [3, 4]])\n", "\n", "A" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 123, "text": [ "array([[1, 2],\n", " [3, 4]])" ] } ], "prompt_number": 123 }, { "cell_type": "code", "collapsed": false, "input": [ "# now B is referring to the same array data as A \n", "B = A " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 124 }, { "cell_type": "code", "collapsed": false, "input": [ "# changing B affects A\n", "B[0,0] = 10\n", "\n", "B" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 125, "text": [ "array([[10, 2],\n", " [ 3, 4]])" ] } ], "prompt_number": 125 }, { "cell_type": "code", "collapsed": false, "input": [ "A" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 126, "text": [ "array([[10, 2],\n", " [ 3, 4]])" ] } ], "prompt_number": 126 }, { "cell_type": "markdown", "metadata": {}, "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 `copy`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "B = copy(A)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 127 }, { "cell_type": "code", "collapsed": false, "input": [ "# now, if we modify B, A is not affected\n", "B[0,0] = -5\n", "\n", "B" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 128, "text": [ "array([[-5, 2],\n", " [ 3, 4]])" ] } ], "prompt_number": 128 }, { "cell_type": "code", "collapsed": false, "input": [ "A" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 129, "text": [ "array([[10, 2],\n", " [ 3, 4]])" ] } ], "prompt_number": 129 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Iterating over array elements" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Generally, we want to avoid iterating over the elements of arrays whenever we can (at all costs). The reason is that in a interpreted language like Python (or MATLAB), iterations are really slow compared to vectorized operations. \n", "\n", "However, sometimes iterations are unavoidable. For such cases, the Python `for` loop is the most convenient way to iterate over an array:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "v = np.array([1,2,3,4])\n", "\n", "for element in v:\n", " print(element)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1\n", "2\n", "3\n", "4\n" ] } ], "prompt_number": 130 }, { "cell_type": "code", "collapsed": false, "input": [ "M = np.array([[1,2], [3,4]])\n", "\n", "for row in M:\n", " print(\"row\", row)\n", " \n", " for element in row:\n", " print(element)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "('row', array([1, 2]))\n", "1\n", "2\n", "('row', array([3, 4]))\n", "3\n", "4\n" ] } ], "prompt_number": 131 }, { "cell_type": "markdown", "metadata": {}, "source": [ "When we need to iterate over each element of an array and modify its elements, it is convenient to use the `enumerate` function to obtain both the element and its index in the `for` loop: " ] }, { "cell_type": "code", "collapsed": false, "input": [ "for row_idx, row in enumerate(M):\n", " print(\"row_idx\", row_idx, \"row\", row)\n", " \n", " for col_idx, element in enumerate(row):\n", " print(\"col_idx\", col_idx, \"element\", element)\n", " \n", " # update the matrix M: square each element\n", " M[row_idx, col_idx] = element ** 2" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "('row_idx', 0, 'row', array([1, 2]))\n", "('col_idx', 0, 'element', 1)\n", "('col_idx', 1, 'element', 2)\n", "('row_idx', 1, 'row', array([3, 4]))\n", "('col_idx', 0, 'element', 3)\n", "('col_idx', 1, 'element', 4)\n" ] } ], "prompt_number": 132 }, { "cell_type": "code", "collapsed": false, "input": [ "# each element in M is now squared\n", "M" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 133, "text": [ "array([[ 1, 4],\n", " [ 9, 16]])" ] } ], "prompt_number": 133 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Vectorizing functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As mentioned several times by now, to get good performance we should try to avoid looping over elements in our vectors and matrices, and instead use vectorized algorithms. The first step in converting a scalar algorithm to a vectorized algorithm is to make sure that the functions we write work with vector inputs." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def Theta(x):\n", " \"\"\"\n", " Scalar implemenation of the Heaviside step function.\n", " \"\"\"\n", " if x >= 0:\n", " return 1\n", " else:\n", " return 0" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 134 }, { "cell_type": "code", "collapsed": false, "input": [ "Theta(np.array([-3,-2,-1,0,1,2,3]))" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\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[0mTheta\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0marray\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;36m3\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[0m", "\u001b[0;32m\u001b[0m in \u001b[0;36mTheta\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0mScalar\u001b[0m \u001b[0mimplemenation\u001b[0m \u001b[0mof\u001b[0m \u001b[0mthe\u001b[0m \u001b[0mHeaviside\u001b[0m \u001b[0mstep\u001b[0m \u001b[0mfunction\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \"\"\"\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m>=\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mValueError\u001b[0m: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()" ] } ], "prompt_number": 135 }, { "cell_type": "markdown", "metadata": {}, "source": [ "OK, that didn't work because we didn't write the `Theta` function so that it can handle with vector input... \n", "\n", "To get a vectorized version of Theta we can use the Numpy function `vectorize`. In many cases it can automatically vectorize a function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "Theta_vec = np.vectorize(Theta)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 136 }, { "cell_type": "code", "collapsed": false, "input": [ "Theta_vec(np.array([-3,-2,-1,0,1,2,3]))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 137, "text": [ "array([0, 0, 0, 1, 1, 1, 1])" ] } ], "prompt_number": 137 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also implement the function to accept vector input from the beginning (requires more effort but might give better performance):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def Theta(x):\n", " \"\"\"\n", " Vector-aware implemenation of the Heaviside step function.\n", " \"\"\"\n", " return 1 * (x >= 0)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 138 }, { "cell_type": "code", "collapsed": false, "input": [ "Theta(np.array([-3,-2,-1,0,1,2,3]))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 139, "text": [ "array([0, 0, 0, 1, 1, 1, 1])" ] } ], "prompt_number": 139 }, { "cell_type": "code", "collapsed": false, "input": [ "# still works for scalars as well\n", "Theta(-1.2), Theta(2.6)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 140, "text": [ "(0, 1)" ] } ], "prompt_number": 140 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Using arrays in conditions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When using arrays in conditions in for example `if` statements and other boolean expressions, one need to use one of `any` or `all`, which requires that any or all elements in the array evalutes to `True`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "M" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 141, "text": [ "array([[ 1, 4],\n", " [ 9, 16]])" ] } ], "prompt_number": 141 }, { "cell_type": "code", "collapsed": false, "input": [ "if (M > 5).any():\n", " print(\"at least one element in M is larger than 5\")\n", "else:\n", " print(\"no element in M is larger than 5\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "at least one element in M is larger than 5\n" ] } ], "prompt_number": 142 }, { "cell_type": "code", "collapsed": false, "input": [ "if (M > 5).all():\n", " print(\"all elements in M are larger than 5\")\n", "else:\n", " print(\"all elements in M are not larger than 5\")" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "all elements in M are not larger than 5\n" ] } ], "prompt_number": 143 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Type casting" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since Numpy arrays are *statically typed*, the type of an array does not change once created. But we can explicitly cast an array of some type to another using the `astype` functions (see also the similar `asarray` function). This always create a new array of new type:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "M.dtype" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 144, "text": [ "dtype('int64')" ] } ], "prompt_number": 144 }, { "cell_type": "code", "collapsed": false, "input": [ "M2 = M.astype(float)\n", "\n", "M2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 145, "text": [ "array([[ 1., 4.],\n", " [ 9., 16.]])" ] } ], "prompt_number": 145 }, { "cell_type": "code", "collapsed": false, "input": [ "M2.dtype" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 146, "text": [ "dtype('float64')" ] } ], "prompt_number": 146 }, { "cell_type": "code", "collapsed": false, "input": [ "M3 = M.astype(bool)\n", "\n", "M3" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 147, "text": [ "array([[ True, True],\n", " [ True, True]], dtype=bool)" ] } ], "prompt_number": 147 }, { "cell_type": "markdown", "metadata": {}, "source": [ "# SciPy" ] }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 147 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Further reading" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* http://numpy.scipy.org\n", "* http://scipy.org/Tentative_NumPy_Tutorial\n", "* http://scipy.org/NumPy_for_Matlab_Users - A Numpy guide for MATLAB users." ] } ], "metadata": {} } ] }