{ "metadata": { "name": "array_object" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "The Numpy array object" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Section contents\n", "\n", "* What are Numpy and Numpy arrays?\n", "* Reference documentation\n", "* Import conventions\n", "* Creating arrays\n", "* Functions for creating arrays\n", "* Basic data types\n", "* Basic visualization\n", "* Indexing and slicing\n", "* Copies and views\n", "* Fancy indexing\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "What are Numpy and Numpy arrays?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Python** objects\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* high-level number objects: integers, floating point\n", "\n", "* containers: lists (costless insertion and append), dictionaries (fast\n", "lookup)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Numpy** provides\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* extension package to Python for multi-dimensional arrays\n", "\n", "* closer to hardware (efficiency)\n", "\n", "* designed for scientific computation (convenience)\n", "\n", "* Also known as *array oriented computing*\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np\n", "a = np.array([0, 1, 2, 3])\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For example, An array containing:\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* values of an experiment/simulation at discrete time steps\n", "\n", "* signal recorded by a measurement device, e.g. sound wave\n", "\n", "* pixels of an image, grey-level or colour\n", "\n", "* 3-D data measured at different X-Y-Z positions, e.g. MRI scan\n", "\n", "* ...\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Why it is useful:** Memory-efficient container that provides fast\n", "numerical operations.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "L = range(1000)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "%timeit [i**2 for i in L]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(1000)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "%timeit a**2" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Reference documentation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* On the web: [http://docs.scipy.org](http://docs.scipy.org)/\n", "\n", "* Interactive help:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.array?" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Looking for something:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.lookfor('create array') " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "np.con*?" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Import conventions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The general convention to import numpy is:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import numpy as np" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using this style of import is recommended.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Creating arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **1-D**:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.array([0, 1, 2, 3])\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a.ndim" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a.shape" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "len(a)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **2-D, 3-D, ...**:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.array([[0, 1, 2], [3, 4, 5]]) # 2 x 3 array\n", "b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b.ndim" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b.shape" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "len(b) # returns the size of the first dimension" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "c = np.array([[[1], [2]], [[3], [4]]])\n", "c" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "c.shape" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Exercise: Simple arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Create simple one and two dimensional arrays. First, redo the examples\n", "from above. And then create your own.\n", "\n", "* Use the functions `len`, `shape` and `ndim` on some of those arrays and\n", "observe their output.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Functions for creating arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In practice, we rarely enter items one by one...\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Evenly spaced:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(10) # 0 .. n-1 (!)\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.arange(1, 9, 2) # start, end (exclusive), step\n", "b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* or by number of points:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "c = np.linspace(0, 1, 6) # start, end, num-points\n", "c" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "d = np.linspace(0, 1, 5, endpoint=False)\n", "d" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Common arrays:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.ones((3, 3)) # reminder: (3, 3) is a tuple\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.zeros((2, 2))\n", "b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "c = np.eye(3)\n", "c" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "d = np.diag(np.array([1, 2, 3, 4]))\n", "d" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `np.random` random numbers (Mersenne Twister PRNG):" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.random.rand(4) # uniform in [0, 1]\n", "a " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.random.randn(4) # Gaussian\n", "b " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "np.random.seed(1234) # Setting the random seed" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Exercise: Creating arrays using functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Experiment with `arange`, `linspace`, `ones`, `zeros`, `eye` and `diag`.\n", "\n", "* Create different kinds of arrays with random numbers.\n", "\n", "* Try setting the seed before creating an array with random values.\n", "\n", "* Look at the function `np.empty`. What does it do? When might this be\n", "useful?\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Basic data types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You may have noticed that, in some instances, array elements are\n", "displayed with a trailing dot (e.g. `2.` vs `2`). This is due to a\n", "difference in the data-type used:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.array([1, 2, 3])\n", "a.dtype" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.array([1., 2., 3.])\n", "b.dtype" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Tip" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Different data-types allow us to store data more compactly in memory,\n", "but most of the time we simply work with floating point numbers. Note\n", "that, in the example above, NumPy auto-detects the data-type from the\n", "input.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can explicitly specify which data-type you want:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "c = np.array([1, 2, 3], dtype=float)\n", "c.dtype" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The **default** data type is floating point:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.ones((3, 3))\n", "a.dtype" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are also other types:\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Complex\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "d = np.array([1+2j, 3+4j, 5+6*1j])\n", "d.dtype" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Bool\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "e = np.array([True, False, False, True])\n", "e.dtype" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Strings\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "f = np.array(['Bonjour', 'Hello', 'Hallo',])\n", "f.dtype # <--- strings containing max. 7 letters" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Much more\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `int32`\n", "\n", "* `int64`\n", "\n", "* `unit32`\n", "\n", "* `unit64`\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Basic visualization" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Tip" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that we have our first data arrays, we are going to visualize them.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Start by launching IPython in *pylab* mode.\n" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "$ ipython --pylab" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or the notebook:\n" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "$ ipython notebook --pylab=inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, if IPython has already been started:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%pylab " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or, from the notebook:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%pylab inline" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `inline` is important for the notebook, so that plots are displayed\n", "in the notebook and not in a new window.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Matplotlib* is a 2D plotting package. We can import its functions as\n", "below:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import matplotlib.pyplot as plt # the tidy way" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And then use (note that you have to use `show` explicitly):\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "plt.plot(x, y) # line plot \n", "plt.show() # <-- shows the plot (not needed with pylab) " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or, if you are using *pylab*:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "plot(x, y) # line plot " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using `import matplotlib.pyplot as plt` is recommended for use in\n", "scripts. Whereas `pylab` is recommended for interactive exploratory\n", "work.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **1D plotting**:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x = np.linspace(0, 3, 20)\n", "y = np.linspace(0, 9, 20)\n", "plt.plot(x, y) # line plot " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "plt.plot(x, y, 'o') # dot plot " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* **2D arrays** (such as images):\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "image = np.random.rand(30, 30)\n", "plt.imshow(image, cmap=plt.cm.hot) \n", "plt.colorbar() " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "More in the Matplotlib tutorial this afternoon\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Exercise: Simple visualizations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Plot some simple arrays.\n", "\n", "* Try to use both the IPython shell and the notebook, if possible.\n", "\n", "* Try using the `gray` colormap.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Indexing and slicing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The items of an array can be accessed and assigned to the same way as\n", "other Python sequences (e.g. lists):\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(10)\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[0], a[2], a[-1]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Warning" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indices begin at 0, like other Python sequences (and C/C++). In\n", "contrast, in Fortran or Matlab, indices begin at 1.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The usual python idiom for reversing a sequence is supported:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a[::-1]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For multidimensional arrays, indexes are tuples of integers:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.diag(np.arange(3))\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[1, 1]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[2, 1] = 10 # third line, second column\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[1]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that:\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* In 2D, the first dimension corresponds to rows, the second to columns.\n", "\n", "* Let us repeat together: the first dimension corresponds to **rows**, the\n", "second to **columns**.\n", "\n", "* for multidimensional `a`, `a[0]` is interpreted by taking all elements\n", "in the unspecified dimensions.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Slicing** Arrays, like other Python sequences can also be sliced:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(10)\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[2:9:3] # [start:end:step]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the last index is not included! :\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a[:4]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All three slice components are not required: by default, \\`start\\` is 0,\n", "\\`end\\` is the last and \\`step\\` is 1:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a[1:3]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[::2]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[3:]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A small illustrated summary of Numpy indexing and slicing...\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from IPython.display import Image\n", "Image(filename='images/numpy_indexing.png')" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also combine assignment and slicing:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(10)\n", "a[5:] = 10\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.arange(5)\n", "a[5:] = b[::-1]\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Exercise: Indexing and slicing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Try the different flavours of slicing, using `start`, `end` and `step`.\n", "\n", "* Verify that the slices in the diagram above are indeed correct. You may\n", "use the following expression to create the array:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.arange(6) + np.arange(0, 51, 10)[:, np.newaxis]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Try assigning a smaller 2D array to a larger 2D array, like in the 1D\n", "example above.\n", "\n", "* Use a different step, e.g. `-2`, in the reversal idiom above. What\n", "effect does this have?\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Exercise: Array creation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create the following arrays (with correct data types):" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "[[1, 1, 1, 1],\n", " [1, 1, 1, 1],\n", " [1, 1, 1, 2],\n", " [1, 6, 1, 1]]\n", "\n", "[[0., 0., 0., 0., 0.],\n", " [2., 0., 0., 0., 0.],\n", " [0., 3., 0., 0., 0.],\n", " [0., 0., 4., 0., 0.],\n", " [0., 0., 0., 5., 0.],\n", " [0., 0., 0., 0., 6.]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Par on course: 3 statements for each\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Hint*: Individual array elements can be accessed similarly to a list,\n", "e.g. `a[1]` or `a[1, 2]`.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Hint*: Examine the docstring for `diag`.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Exercise: Tiling for array creation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Skim through the documentation for `np.tile`, and use this function to\n", "construct the array:" ] }, { "cell_type": "raw", "metadata": {}, "source": [ "[[4, 3, 4, 3, 4, 3],\n", " [2, 1, 2, 1, 2, 1],\n", " [4, 3, 4, 3, 4, 3],\n", " [2, 1, 2, 1, 2, 1]]" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Copies and views" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A slicing operation creates a **view** on the original array, which is\n", "just a way of accessing array data. Thus the original array is not\n", "copied in memory. You can use `np.may_share_memory()` to check if two\n", "arrays share the same memory block. Note however, that this uses\n", "heuristics and may give you false positives.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**When modifying the view, the original array is modified as well**:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(10)\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b = a[::2]\n", "b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "np.may_share_memory(a, b)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "b[0] = 12\n", "b" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a # (!)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(10)\n", "c = a[::2].copy() # force a copy\n", "c[0] = 12\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "np.may_share_memory(a, c)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This behavior can be surprising at first sight... but it allows to save\n", "both memory and time.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Worked example: Prime number sieve" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from IPython.display import Image\n", "Image(filename='images/prime-sieve.png')" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Compute prime numbers in 0--99, with a sieve\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Construct a shape (100,) boolean array `is_prime`, filled with True in\n", "the beginning:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "is_prime = np.ones((100,), dtype=bool)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Cross out 0 and 1 which are not primes:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "is_prime[:2] = 0" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* For each integer `j` starting from 2, cross out its higher multiples:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "N_max = int(np.sqrt(len(is_prime)))\n", "for j in range(2, N_max):\n", " is_prime[2*j::j] = False" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Skim through `help(np.nonzero)`, and print the prime numbers\n", "\n", "* Follow-up:\n", "\n", " * Move the above code into a script file named `prime_sieve.py`\n", "\n", " * Run it to check it works\n", "\n", " * Use the optimization suggested in [the sieve of\n", "Eratosthenes](http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes):\n", "\n", " * Skip `j` which are already known to not be primes\n", "\n", " * The first number to cross out is $j^2$\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Fancy indexing" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Tip" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Numpy arrays can be indexed with slices, but also with boolean or\n", "integer arrays (**masks**). This method is called *fancy indexing*. It\n", "creates **copies not views**.\n" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Using boolean masks" ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.random.seed(3)\n", "a = np.random.random_integers(0, 20, 15)\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "(a % 3 == 0)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "mask = (a % 3 == 0)\n", "extract_from_a = a[mask] # or, a[a%3==0]\n", "extract_from_a # extract a sub-array with the mask" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indexing with a mask can be very useful to assign a new value to a\n", "sub-array:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a[a % 3 == 0] = -1\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Indexing with an array of integers" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(0, 100, 10)\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indexing can be done with an array of integers, where the same index is\n", "repeated several time:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a[[2, 3, 2, 4, 2]] # note: [2, 3, 2, 4, 2] is a Python list" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "New values can be assigned with this kind of indexing:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a[[9, 7]] = -100\n", "a" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Tip" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When a new array is created by indexing with an array of integers, the\n", "new array has the same shape than the array of integers:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.arange(10)\n", "idx = np.array([[3, 4], [9, 7]])\n", "idx.shape" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "a[idx]" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The image below illustrates various fancy indexing applications\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from IPython.display import Image\n", "Image(filename='images/numpy_fancy_indexing.png')" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Exercise: Fancy indexing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Again, verify the fancy indexing shown in the diagram above.\n", "\n", "* Use fancy indexing on the left and array creation on the right to assign\n", "values from a smaller array to a larger array.\n" ] } ], "metadata": {} } ] }