{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Indexing and Slicing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setting up the data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.37188258,  0.55062526,  0.91109445,  0.52792531,  0.02249503,\n",
       "        0.98267557,  0.4525032 ,  0.22061845,  0.43624253,  0.51826583])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# a vector: the argument to the array function is a Python list\n",
    "v = np.random.rand(10)\n",
    "v"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.91728287,  0.17639295],\n",
       "       [ 0.14874153,  0.8201578 ],\n",
       "       [ 0.33937767,  0.29744809],\n",
       "       [ 0.89336889,  0.38915789],\n",
       "       [ 0.45762626,  0.21877071],\n",
       "       [ 0.23448393,  0.8950091 ],\n",
       "       [ 0.89477702,  0.03326833],\n",
       "       [ 0.34073951,  0.69822947],\n",
       "       [ 0.58063668,  0.38180403],\n",
       "       [ 0.09361408,  0.24731792]])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# a matrix: the argument to the array function is a nested Python list\n",
    "M = np.random.rand(10, 2)\n",
    "M"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Indexing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "source": [
    "We can index elements in an array using the square bracket and indices:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.37188257782888778"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# v is a vector, and has only one dimension, taking one index\n",
    "v[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.82015780105919578"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# M is a matrix, or a 2 dimensional array, taking two indices \n",
    "M[1,1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "If we omit an index of a multidimensional array it returns the whole row (or, in general, a N-1 dimensional array) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.91728287,  0.17639295],\n",
       "       [ 0.14874153,  0.8201578 ],\n",
       "       [ 0.33937767,  0.29744809],\n",
       "       [ 0.89336889,  0.38915789],\n",
       "       [ 0.45762626,  0.21877071],\n",
       "       [ 0.23448393,  0.8950091 ],\n",
       "       [ 0.89477702,  0.03326833],\n",
       "       [ 0.34073951,  0.69822947],\n",
       "       [ 0.58063668,  0.38180403],\n",
       "       [ 0.09361408,  0.24731792]])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.14874153,  0.8201578 ])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M[1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "The same thing can be achieved with using `:` instead of an index: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.14874153,  0.8201578 ])"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M[1,:] # row 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0.17639295,  0.8201578 ,  0.29744809,  0.38915789,  0.21877071,\n",
       "        0.8950091 ,  0.03326833,  0.69822947,  0.38180403,  0.24731792])"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M[:,1] # column 1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "We can assign new values to elements in an array using indexing:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "M[0,0] = 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.        ,  0.17639295],\n",
       "       [ 0.14874153,  0.8201578 ],\n",
       "       [ 0.33937767,  0.29744809],\n",
       "       [ 0.89336889,  0.38915789],\n",
       "       [ 0.45762626,  0.21877071],\n",
       "       [ 0.23448393,  0.8950091 ],\n",
       "       [ 0.89477702,  0.03326833],\n",
       "       [ 0.34073951,  0.69822947],\n",
       "       [ 0.58063668,  0.38180403],\n",
       "       [ 0.09361408,  0.24731792]])"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "# also works for rows and columns\n",
    "M[1,:] = 0\n",
    "M[:,1] = -1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1.        , -1.        ],\n",
       "       [ 0.        , -1.        ],\n",
       "       [ 0.33937767, -1.        ],\n",
       "       [ 0.89336889, -1.        ],\n",
       "       [ 0.45762626, -1.        ],\n",
       "       [ 0.23448393, -1.        ],\n",
       "       [ 0.89477702, -1.        ],\n",
       "       [ 0.34073951, -1.        ],\n",
       "       [ 0.58063668, -1.        ],\n",
       "       [ 0.09361408, -1.        ]])"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Index slicing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "Index slicing is the technical name for the syntax `M[lower:upper:step]` to extract part of an array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([1, 2, 3, 4, 5])"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = np.array([1,2,3,4,5])\n",
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2, 3])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[1:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "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",
   "execution_count": 30,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1, -2, -3,  4,  5])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[1:3] = [-2,-3]\n",
    "\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "* We can omit any of the three parameters in `M[lower:upper:step]`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1, -2, -3,  4,  5])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[::] # lower, upper, step all take the default values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1, -3,  5])"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[::2] # step is 2, lower and upper defaults to the beginning and end of the array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 1, -2, -3])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[:3] # first three elements"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([4, 5])"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[3:] # elements from index 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "* Negative indices counts from the end of the array (positive index from the begining):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "a = np.array([1,2,3,4,5])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[-1] # the last element in the array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([3, 4, 5])"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a[-3:] # the last three elements"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "* Index slicing works exactly the same way for multidimensional arrays:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "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": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "A = np.array([[n+m*10 for n in range(5)] for m in range(5)])\n",
    "A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[11, 12, 13],\n",
       "       [21, 22, 23],\n",
       "       [31, 32, 33]])"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# a block from the original array\n",
    "A[1:4, 1:4]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  2,  4],\n",
       "       [20, 22, 24],\n",
       "       [40, 42, 44]])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# strides\n",
    "A[::2, ::2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "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",
   "execution_count": 42,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[10, 11, 12, 13, 14],\n",
       "       [20, 21, 22, 23, 24],\n",
       "       [30, 31, 32, 33, 34]])"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "row_indices = [1, 2, 3]\n",
    "A[row_indices]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([11, 22, 34])"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "col_indices = [1, 2, -1] # remember, index -1 means the last element\n",
    "A[row_indices, col_indices]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "* We can also index **masks**: \n",
    "\n",
    "    - 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",
   "execution_count": 46,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 1, 2, 3, 4])"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b = np.array([n for n in range(5)])\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 2])"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "row_mask = np.array([True, False, True, False, False])\n",
    "b[row_mask]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Alternatively:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 2])"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# same thing\n",
    "row_mask = np.array([1,0,1,0,0], dtype=bool)\n",
    "b[row_mask]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "This feature is very useful to conditionally select elements from an array, using for example comparison operators:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "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])"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.arange(0, 10, 0.5)\n",
    "x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "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)"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mask = (5 < x) * (x < 7.5)\n",
    "\n",
    "mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "-"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5.5,  6. ,  6.5,  7. ])"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[mask]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Indexing and Array Memory Management"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Numpy arrays support two different way of storing data into memory, namely\n",
    "\n",
    "* F-Contiguous \n",
    "    - i.e. *column-wise* storage, Fortran-like\n",
    "* C-Contiguous\n",
    "    - i.e. *row-wise* storage, C-like\n",
    "    \n",
    "The **storage** strategy is controlled by the parameter `order` of `np.array`\n",
    "\n",
    "<img src=\"images/storage_simple.png\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's an example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "FC = np.array([[1, 2, 3],    [4, 5, 6], \n",
    "               [7, 8, 9],    [10, 11, 12]], order='F')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "CC = np.array([[1, 2, 3],    [4, 5, 6], \n",
    "               [7, 8, 9],    [10, 11, 12]], order='C')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* **Note**: no changes in meaning for indexing operations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "FC[0, 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "CC[0, 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4, 3)"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "FC.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4, 3)"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "CC.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"images/storage_index.png\" />"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "## Functions for extracting data from arrays and creating arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### `np.where`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "-"
    }
   },
   "source": [
    "The index mask can be converted to position index using the `np.where` function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(array([11, 12, 13, 14]),)"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "indices = np.where(mask)\n",
    "\n",
    "indices"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5.5,  6. ,  6.5,  7. ])"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x[indices] # this indexing is equivalent to the fancy indexing x[mask]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### `np.diag`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With the `np.diag` function we can also extract the diagonal and subdiagonals of an array:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 0, 11, 22, 33, 44])"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.diag(A)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([10, 21, 32, 43])"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.diag(A, -1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### `np.take`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `np.take` function is similar to fancy indexing described above:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-3, -2, -1,  0,  1,  2])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v2 = np.arange(-3,3)\n",
    "v2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-2,  0,  2])"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "row_indices = [1, 3, 5]\n",
    "v2[row_indices] # fancy indexing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-2,  0,  2])"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "v2.take(row_indices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "* But `take` also works on lists and other objects:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([-2,  0,  2])"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.take([-3, -2, -1,  0,  1,  2], row_indices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### `np.choose`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Constructs and array by picking elements form several arrays:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 5, -2,  5, -2])"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "which = [1, 0, 1, 0]\n",
    "choices = [[-2,-2,-2,-2], [5,5,5,5]]\n",
    "\n",
    "np.choose(which, choices)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "## Computations on subsets of arrays"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can compute with subsets of the data in an array using indexing, fancy indexing, and the other methods of extracting data from an array (described above)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "data = np.random.randn(77431, 3)\n",
    "months_of_the_year = np.arange(1, 13)\n",
    "data[:, 1] = np.random.choice(months_of_the_year, size=data.shape[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([  1.,   2.,   3.,   4.,   5.,   6.,   7.,   8.,   9.,  10.,  11.,\n",
       "        12.])"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.unique(data[:,1]) # the month column takes values from 1 to 12"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "mask_feb = data[:,1] == 2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Brief Preview (of some of the things presented in next notebooks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.013449501337473352"
      ]
     },
     "execution_count": 82,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# compute the mean of values in column 2 (the third one)\n",
    "np.mean(data[mask_feb,2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "With these tools we have very powerful data processing capabilities at our disposal. For example, to extract the average monthly average temperatures for each month of the year only takes a few lines of code: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZIAAAEPCAYAAABoekJnAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAGbpJREFUeJzt3X2UJXV95/H3x5kQdEGRrILAeEAFBUTFJDhHkrUxkjMZ\nNpBks9HZTRTcjUbFuOpZEckunbMnUYzGJ46KCi5qBA0ag8sYREMbN2ZBFMYRZoBRWXlYRoNBDDkq\nyHf/uDVwp+2H27fu7dvV836dc8/cqvpV1bd76vb3/p6qUlVIkjSsh006AElSt5lIJEmtmEgkSa2Y\nSCRJrZhIJEmtmEgkSa1MNJEk2ZBke5Kbk5wxT5l3Ntu3JDm2Wbd3kquSXJfkhiRvXN7IJUm7TCyR\nJFkDnAtsAI4CNiU5claZjcCTqupw4CXAewCq6ofACVX1DOBpwAlJfmk545ck9UyyRnIcsKOqbqmq\n+4CLgVNmlTkZuBCgqq4C9ktyQLP8L02ZvYA1wPeWJWpJ0m4mmUgOBm7tW76tWbdYmUOgV6NJch2w\nE7iyqm4YY6ySpHlMMpEMem+WzLVfVf2kado6BPg3SaZGGJskaUBrJ3ju24F1fcvr6NU4FipzSLPu\nQVX1/SSXAb8AzPRvS+KNxCRpCFU1+0v8vCZZI7kGODzJoUn2Ap4PXDqrzKXACwGSrAfurqqdSf51\nkv2a9Q8HTgSuneskVdXZ19lnnz3xGPbU+Lscu/FP/tX1+JdqYjWSqro/yenA5fQ6y8+vqm1JXtps\nP6+qNifZmGQHcC9wWrP744ALkzyMXjL8cFV9fgI/hiTt8SbZtEVVfQb4zKx1581aPn2O/bYCzxxv\ndJKkQTizfQWbmpqadAitdDn+LscOxj9pXY9/qTJMe1hXJKnV/PNJ0jgkoTrS2S5JWgVMJJKkVkwk\nkqRWTCSSpFZMJJKkVkwkkqRWTCSSpFZMJJKkVkwkkqRWTCSSpFYmetNGaaVKBr47xMC8XY9WKxOJ\nNK9R/uEffWKSVgqbtiRJrZhIJEmtmEgkSa2YSCRJrZhIJEmtmEgkSa2YSCRJrZhIJEmtmEgkSa2Y\nSCRJrZhIJEmtmEgkSa2YSCRJrZhIJEmtTDSRJNmQZHuSm5OcMU+ZdzbbtyQ5tlm3LsmVSa5P8vUk\nf7i8kUuSdplYIkmyBjgX2AAcBWxKcuSsMhuBJ1XV4cBLgPc0m+4DXl1VRwPrgVfM3leStDwmWSM5\n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\n1b9QVZWk5ig317rZ5zgL+HFVfXS4KCWtRFWLfvy1gowtkVTVifNtS7IzyYFVdWeSxwHfmaPY7cC6\nvuV19Golu45xKrAR+JWF4pienn7w/dTUFFNTUwNEL0l7jpmZGWZmZobeP5PI/EneDNxVVeckeT2w\nX1W9flaZtcCN9BLFHcDVwKaq2pZkA/BW4DlV9Y8LnKf8ZiNptiQM0Ogx6NFWXQ0qCVU1cLvgpBLJ\n/sDHgccDtwC/U1V3JzkIeH9VndSU+zXg7cAa4PyqemOz/mZgL+B7zSH/oapePsd5TCSSfkovkYzO\navs704lEslxMJJK0dEtNJM5slyS1YiKRJLViIpEktWIikSS1YiKRJLViIpEktWIikSS1YiKRJLVi\nIpEktWIikSS1YiKRJLViIpEktWIikSS1YiKRJLViIpEktWIikSS1YiKRJLViIpEktWIikSS1YiKR\nJLViIpEktWIikSS1YiKRJLViIpEktWIikSS1YiKRJLViIpEktWIikSS1MpFEkmT/JFckuSnJZ5Ps\nN0+5DUm2J7k5yRl96/9Hki1Jrkvy+STrli96SVK/SdVIXg9cUVVHAJ9vlneTZA1wLrABOArYlOTI\nZvObq+rpVfUM4FPA2csT9vKamZmZdAitdDn+LscOxj9pXY9/qSaVSE4GLmzeXwj8xhxljgN2VNUt\nVXUfcDFwCkBV/aCv3D7AP44x1onp+sXY5fi7HDsY/6R1Pf6lWjuh8x5QVTub9zuBA+YoczBwa9/y\nbcCzdi0k+RPg94B/AdaPKU5J0iLGViNp+kC2zvE6ub9cVRVQcxxirnX9+51VVY8H/ifwtpEFLkla\nkvT+ji/zSZPtwFRV3ZnkccCVVfWUWWXWA9NVtaFZPhN4oKrOmVXu8cDmqnrqHOdZ/h9OklaBqsqg\nZSfVtHUp8CLgnObfT81R5hrg8CSHAncAzwc2ASQ5vKpubsqdAlw710mW8ouQJA1nUjWS/YGPA48H\nbgF+p6ruTnIQ8P6qOqkp92vA24E1wPlV9cZm/SXAk4GfAN8AXlZV31n2H0SSNJlEIklaPVblzPb5\nJjJ2QZJ1Sa5Mcn2Sryf5w0nHNIwka5Jcm+TTk45lqZLsl+SSJNuS3ND013VGkjOb62drko8m+dlJ\nx7SQJBck2Zlka9+6gSYtrwTzxP9nzfWzJcknkzxqkjHOZ67Y+7a9NskDTQvSglZdIllkImMX3Ae8\nuqqOpjes+RUdi3+XVwE3sMjouxXqHfQGcBwJPA3YNuF4Btb0Kf4+8MyqOoZes/ALJhnTAD5I7/Pa\nb9FJyyvIXPF/Fji6qp4O3AScuexRDWau2GnuFnIi8H8HOciqSyQsMJGxC6rqzqq6rnn/z/T+iB00\n2aiWJskhwEbgA0CnBjw03xx/uaouAKiq+6vq+xMOaynuofdl5BFJ1gKPAG6fbEgLq6ovAv80a/Ug\nk5ZXhLnir6orquqBZvEq4JBlD2wA8/zuAf4ceN2gx1mNiWSuiYwHTyiWVppvl8fSuxC75G3AfwUe\nWKzgCnQY8N0kH0zy1STvT/KISQc1qKr6HvBW4Nv0RjveXVWfm2xUQxlk0nJXvBjYPOkgBpXkFOC2\nqvraoPusxkTSxaaUn5JkH+AS4FVNzaQTkvxb4DtVdS0dq4001gLPBN5dVc8E7mVlN6vsJskTgf8C\nHEqvJrtPkv840aBaWmDS8oqX5Czgx1X10UnHMojmS9Mb2P3+hYt+jldjIrkd6L8b8Dp6tZLOSPIz\nwCeAj1TVXHNsVrJnAycn+RZwEfDcJB+acExLcRu9b2NfbpYvoZdYuuIXgC9V1V1VdT/wSXr/J12z\nM8mBAM2k5c4N709yKr0m3i4l8ifS+xKypfkMHwJ8JcljF9ppNSaSBycyJtmL3kTGSycc08CSBDgf\nuKGq3j7peJaqqt5QVeuq6jB6nbx/W1UvnHRcg6qqO4FbkxzRrHoecP0EQ1qq7cD6JA9vrqXn0Rv0\n0DW7Ji3D/JOWV6wkG+g1755SVT+cdDyDqqqtVXVAVR3WfIZvozdwY8FEvuoSSfMt7HTgcnofoI9V\nVWdG3QDHA78LnNAMn722uSi7qotNEq8E/iLJFnqjtv50wvEMrKq2AB+i94VqVxv3+yYX0eKSXAR8\nCXhykluTnAa8CTgxyU3Ac5vlFWmO+F8MvIvencmvaD7D755okPPoi/2Ivt99v4E+v05IlCS1supq\nJJKk5WUikSS1YiKRJLViIpEktWIikSS1YiKRJLViIpFaaG6z/eG+5bVJvjvs7fOTPCrJy/qWp7p4\nK37tWUwkUjv3Akcn2btZPpHebOBhJ2g9Gnj5KAKTlouJRGpvM3BS834TvXuMBR58QNOnmgcc/UOS\nY5r1081Dha5M8o0kr2z2fxPwxGY29JvpJaR9kvxl86CkjyzvjyYtzkQitfcx4AXNkwiPYffb/v8x\n8JXmAUdvoHf7kl2OAH6V3jN0zm4eynYG8I2qOraqXkcvIR1L70FhRwFPSHL8uH8gaSlMJFJLVbWV\n3h1TNwGXzdp8PPDhptyVwM8l2ZdeTeOyqrqvqu6id3fbA5j7lt1XV9Udze3Ur2vOJa0YaycdgLRK\nXAq8BXgO8JhZ2+Z7nsOP+97/hPk/jz8asJw0EdZIpNG4AJiuqtm3nP8izfMokkwB362qHzB/cvkB\nsO+4gpTGwW82UjsFUFW3A+f2rds1amsauKC5Jf29PPSMjTmf+ldVdyX5+yRb6XXib56jnLfs1ori\nbeQlSa3YtCVJasVEIklqxUQiSWrFRCJJasVEIklqxUQiSWrFRCJJasVEIklq5f8DdkfF7aiEiNcA\nAAAASUVORK5CYII=\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x10f196a20>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "months = np.arange(1,13)\n",
    "monthly_mean = [np.mean(data[data[:,1] == month, 2]) for month in months]\n",
    "\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "fig, ax = plt.subplots()\n",
    "ax.bar(months, monthly_mean)\n",
    "ax.set_xlabel(\"Month\")\n",
    "ax.set_ylabel(\"Monthly avg. temp.\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "source": [
    "# Iterating over array elements"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "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",
   "execution_count": 85,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "v = np.array([1,2,3,4])\n",
    "\n",
    "for element in v:\n",
    "    print(element)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "row [1 2]\n",
      "1\n",
      "2\n",
      "row [3 4]\n",
      "3\n",
      "4\n"
     ]
    }
   ],
   "source": [
    "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)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "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",
   "execution_count": 87,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "row_idx 0 row [1 2]\n",
      "col_idx 0 element 1\n",
      "col_idx 1 element 2\n",
      "row_idx 1 row [3 4]\n",
      "col_idx 0 element 3\n",
      "col_idx 1 element 4\n"
     ]
    }
   ],
   "source": [
    "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"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  4],\n",
       "       [ 9, 16]])"
      ]
     },
     "execution_count": 88,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# each element in M is now squared\n",
    "M"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "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",
   "execution_count": 89,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [],
   "source": [
    "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"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "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": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-90-6658efdd2f22>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mTheta\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<ipython-input-89-9a0cb13d93d4>\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()"
     ]
    }
   ],
   "source": [
    "Theta(array([-3,-2,-1,0,1,2,3]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "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 `np.vectorize`. In many cases it can automatically vectorize a function:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `np.vectorize`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [],
   "source": [
    "Theta_vec = np.vectorize(Theta)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([0, 0, 0, 1, 1, 1, 1])"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "Theta_vec(array([-3,-2,-1,0,1,2,3]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### `np.frompyfunc`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Universal functions** (Ufuncs) work on arrays, element-by-element, or on scalars. \n",
    "\n",
    "Ufuncs accept a set of scalars as input, and produce a set of scalars as output."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Result:  [1 1 1 1]\n"
     ]
    }
   ],
   "source": [
    "Theta_vec = np.frompyfunc(Theta, 1, 1)\n",
    "print(\"Result: \", ufunc(np.arange(4)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Excercise"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "source": [
    "### Avoiding Vectorize\n",
    "\n",
    "* Implement the function to accept vector input from the beginning \n",
    "    - This requires \"more effort\" but might give better performance"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%load \"solutions/sol_021.py\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "slideshow": {
     "slide_type": "slide"
    }
   },
   "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",
   "execution_count": 102,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 1,  4],\n",
       "       [ 9, 16]])"
      ]
     },
     "execution_count": 102,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "M"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "subslide"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "at least one element in M is larger than 5\n"
     ]
    }
   ],
   "source": [
    "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\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {
    "collapsed": false,
    "slideshow": {
     "slide_type": "fragment"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "all elements in M are not larger than 5\n"
     ]
    }
   ],
   "source": [
    "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\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
