{ "cells": [ { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "from __future__ import print_function" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# NumPy" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "this notebook is based on the SciPy NumPy tutorial" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "
Note that the traditional way to import numpy is to rename it np. This saves on typing and makes your code a little more compact.
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "NumPy provides a multidimensional array class as well as a _large_ number of functions that operate on arrays.\n", "\n", "NumPy arrays allow you to write fast (optimized) code that works on arrays of data. To do this, there are some restrictions on arrays:\n", "\n", "* all elements are of the same data type (e.g. float)\n", "* the size of the array is fixed in memory, and specified when you create the array (e.g., you cannot grow the array like you do with lists)\n", "\n", "The nice part is that arithmetic operations work on entire arrays—this means that you can avoid writing loops in python (which tend to be slow). Instead the \"looping\" is done in the underlying compiled code" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Array Creation and Properties" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "There are a lot of ways to create arrays. Let's look at a few\n", "\n", "Here we create an array using `arange` and then change its shape to be 3 rows and 5 columns. Note the _row-major ordering_—you'll see that the rows are together in the inner `[]` (more on this in a bit)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(15)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(15).reshape(3,5)\n", "\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "an array is an object of the `ndarray` class, and it has methods that know how to work on the array data. Here, `.reshape()` is one of the many methods." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "A NumPy array has a lot of meta-data associated with it describing its shape, datatype, etc." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(a.ndim)\n", "print(a.shape)\n", "print(a.size)\n", "print(a.dtype)\n", "print(a.itemsize)\n", "print(type(a))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "help(a)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "we can also create an array from a list" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "b = np.array( [1.0, 2.0, 3.0, 4.0] )\n", "print(b)\n", "print(b.dtype)\n", "print(type(b))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "we can create a multi-dimensional array of a specified size initialized all to 0 easily, using the `zeros()` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "b = np.zeros((10,8))\n", "b" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "There is also an analogous ones() and empty() array routine. Note that here we can explicitly set the datatype for the array in this function if we wish. \n", "\n", "Unlike lists in python, all of the elements of a numpy array are of the same datatype" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "c = np.eye(10, dtype=np.float64)\n", "c" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "`linspace` creates an array with evenly space numbers. The `endpoint` optional argument specifies whether the upper range is in the array or not" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "d = np.linspace(0, 1, 10, endpoint=False)\n", "print(d)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "

Quick Exercise:

\n", "\n", "Analogous to `linspace()`, there is a `logspace()` function that creates an array with elements equally spaced in log. Use `help(np.logspace)` to see the arguments, and create an array with 10 elements from $10^{-6}$ to $10^3$.\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "we can also initialize an array based on a function" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "f = np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int)\n", "f" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Array Operations" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "most operations (`+`, `-`, `*`, `/`) will work on an entire array at once, element-by-element.\n", "\n", "Note that that the multiplication operator is not a matrix multiply (there is a new operator in python 3.5+, `@`, to do matrix multiplicaiton.\n", "\n", "Let's create a simply array to start with" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(12).reshape(3,4)\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Multiplication by a scalar multiplies every element" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a*2" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "adding two arrays adds element-by-element" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a + a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "multiplying two arrays multiplies element-by-element" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a*a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "We can think of our 2-d array as a 3 x 5 matrix (3 rows, 5 columns). We can take the transpose to geta 5 x 3 matrix, and then we can do a matrix multiplication" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Quick Exercise:

\n", "\n", "What do you think `1./a` will do? Try it and see\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "b = a.transpose()\n", "b" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a @ b" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "We can sum the elements of an array:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a.sum()" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "

Quick Exercise:

\n", "\n", "`sum()` takes an optional argument, `axis=N`, where `N` is the axis to sum over. Sum the elements of `a` across rows to create an array with just the sum along each column of `a`.\n", "\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "We can also easily get the extrema" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(a.min(), a.max())" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "## universal functions" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "universal functions work element-by-element. Let's create a new array scaled by `pi`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "b = a*np.pi/12.0\n", "print(b)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "c = np.cos(b)\n", "print(c)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "d = b + c " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(d)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "

Quick Exercise:

\n", "\n", "We will often want to write our own function that operates on an array and returns a new array. We can do this just like we did with functions previously—the key is to use the methods from the `np` module to do any operations, since they work on, and return, arrays.\n", "\n", "Write a simple function that returns $\\sin(2\\pi x)$ for an input array `x`. Then test it \n", "by passing in an array `x` that you create via `linspace()`\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Slicing" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "slicing works very similarly to how we saw with strings. Remember, python uses 0-based indexing\n", "\n", "![](slicing.png)\n", "\n", "Let's create this array from the image:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(9)\n", "a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Now look at accessing a single element vs. a range (using slicing)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Giving a single (0-based) index just references a single value" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[2]" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Giving a range uses the range of the edges to return the values" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(a[2:3])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[2:4]" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "The `:` can be used to specify all of the elements in that dimension" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[:]" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "## Multidimensional Arrays\n", "\n", "Multidimensional arrays are stored in a contiguous space in memory -- this means that the columns / rows need to be unraveled (flattened) so that it can be thought of as a single one-dimensional array. Different programming languages do this via different conventions:\n", "\n", "![](row_column_major.png)\n", "\n", "Storage order:\n", "\n", "* Python/C use *row-major* storage: rows are stored one after the other\n", "* Fortran/matlab use *column-major* storage: columns are stored one after another\n", "\n", "The ordering matters when \n", "\n", "* passing arrays between languages (we'll talk about this later this semester)\n", "* looping over arrays -- you want to access elements that are next to one-another in memory\n", " * e.g, in Fortran:\n", " ```\n", " double precision :: A(M,N)\n", " do j = 1, N\n", " do i = 1, M\n", " A(i,j) = …\n", " enddo\n", " enddo\n", " ```\n", " \n", " * in C\n", " ```\n", " double A[M][N];\n", " for (i = 0; i < M; i++) {\n", " for (j = 0; j < N; j++) {\n", " A[i][j] = …\n", " }\n", " } \n", " ```\n", " \n", "\n", "In python, using NumPy, we'll try to avoid explicit loops over elements as much as possible\n", "\n", "Let's look at multidimensional arrays:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(15).reshape(3,5)\n", "a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Notice that the output of `a` shows the row-major storage. The rows are grouped together in the inner `[...]`\n", "\n", "Giving a single index (0-based) for each dimension just references a single value in the array" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[1,1]" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Doing slices will access a range of elements. Think of the start and stop in the slice as referencing the left-edge of the slots in the array." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[0:2,0:2]" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Access a specific column" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[:,1]" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Sometimes we want a one-dimensional view into the array -- here we see the memory layout (row-major) more explicitly" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a.flatten()" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "we can also iterate -- this is done over the first axis (rows)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "for row in a:\n", " print(row)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "or element by element" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "for e in a.flat:\n", " print(e)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Generally speaking, we want to avoid looping over the elements of an array in python—this is slow. Instead we want to write and use functions that operate on the entire array at once." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

Quick Exercise:

\n", "\n", "Consider the array defined as:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "q = np.array([[1, 2, 3, 2, 1],\n", " [2, 4, 4, 4, 2],\n", " [3, 4, 4, 4, 3],\n", " [2, 4, 4, 4, 2],\n", " [1, 2, 3, 2, 1]])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " * using slice notation, create an array that consists of only the `4`'s in `q` (this will be called a _view_, as we'll see shortly)\n", " * zero out all of the elements in your view\n", " * how does `q` change?\n", "
" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Copying Arrays" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "simply using \"=\" does not make a copy, but much like with lists, you will just have multiple names pointing to the same ndarray object\n", "\n", "Therefore, we need to understand if two arrays, `A` and `B` point to:\n", "* the same array, including shape and data/memory space\n", "* the same data/memory space, but perhaps different shapes (a _view_)\n", "* a separate cpy of the data (i.e. stored completely separately in memory)\n", "\n", "All of these are possible:\n", "* `B = A`\n", " \n", " this is _assignment_. No copy is made. `A` and `B` point to the same data in memory and share the same shape, etc. They are just two different labels for the same object in memory\n", " \n", "\n", "* `B = A[:]`\n", "\n", " this is a _view_ or _shallow copy_. The shape info for A and B are stored independently, but both point to the same memory location for data\n", " \n", " \n", "* `B = A.copy()`\n", "\n", " this is a _deep_ copy. A completely separate object will be created in memory, with a completely separate location in memory.\n", " \n", "Let's look at examples" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(10)\n", "print(a)\n" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Here is assignment—we can just use the `is` operator to test for equality" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "b = a\n", "b is a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Since `b` and `a` are the same, changes to the shape of one are reflected in the other—no copy is made." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "b.shape = (2, 5)\n", "print(b)\n", "a.shape" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "b is a" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(a)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "a shallow copy creates a new *view* into the array—the _data_ is the same, but the array properties can be different" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(12)\n", "c = a[:]\n", "a.shape = (3,4)\n", "\n", "print(a)\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "since the underlying data is the same memory, changing an element of one is reflected in the other" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "c[1] = -1\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Even slices into an array are just views, still pointing to the same memory" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "d = c[3:8]\n", "print(d)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "d[:] = 0 " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(a)\n", "print(c)\n", "print(d)" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true, "deletable": true, "editable": true }, "source": [ "There are lots of ways to inquire if two arrays are the same, views, own their own data, etc" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(c is a)\n", "print(c.base is a)\n", "print(c.flags.owndata)\n", "print(a.flags.owndata)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "to make a copy of the data of the array that you can deal with independently of the original, you need a _deep copy_" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "d = a.copy()\n", "d[:,:] = 0.0\n", "\n", "print(a)\n", "print(d)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Boolean Indexing" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "There are lots of fun ways to index arrays to access only those elements that meet a certain condition" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(12).reshape(3,4)\n", "a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Here we set all the elements in the array that are > 4 to zero" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[a > 4] = 0\n", "a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "and now, all the zeros to -1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a[a == 0] = -1\n", "a" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a == -1" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "if we have 2 tests, we need to use `logical_and()` or `logical_or()`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a = np.arange(12).reshape(3,4)\n", "a[np.logical_and(a > 3, a <= 9)] = 0.0\n", "a" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Our test that we index the array with returns a boolean array of the same shape:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "a > 4" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Avoiding Loops" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "In general, you want to avoid loops over elements on an array.\n", "\n", "Here, let's create 1-d x and y coordinates and then try to fill some larger array" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "M = 32\n", "N = 64\n", "xmin = ymin = 0.0\n", "xmax = ymax = 1.0\n", "\n", "x = np.linspace(xmin, xmax, M, endpoint=False)\n", "y = np.linspace(ymin, ymax, N, endpoint=False)\n", "\n", "print(x.shape)\n", "print(y.shape)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "we'll time out code" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "import time" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "t0 = time.time()\n", "\n", "g = np.zeros((M, N))\n", "\n", "for i in range(M):\n", " for j in range(N):\n", " g[i,j] = np.sin(2.0*np.pi*x[i]*y[j])\n", " \n", "t1 = time.time()\n", "print(\"time elapsed: {} s\".format(t1-t0))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Now let's instead do this using all array syntax. First will extend our 1-d coordinate arrays to be 2-d. NumPy has a function for this (`meshgrid()`)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "x2d, y2d = np.meshgrid(x, y, indexing=\"ij\")\n", "\n", "print(x2d[:,0])\n", "print(x2d[0,:])\n", "\n", "print(y2d[:,0])\n", "print(y2d[0,:])" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "t0 = time.time()\n", "g2 = np.sin(2.0*np.pi*x2d*y2d)\n", "t1 = time.time()\n", "print(\"time elapsed: {} s\".format(t1-t0))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "print(np.max(np.abs(g2-g)))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "### Numerical differencing on NumPy arrays" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Now we want to construct a derivative, \n", "$$\n", "\\frac{d f}{dx}\n", "$$" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "x = np.linspace(0, 2*np.pi, 25)\n", "f = np.sin(x)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "We want to do this without loops—we'll use views into arrays offset from one another. Recall from calculus that a derivative is approximately:\n", "$$\n", "\\frac{df}{dx} = \\frac{f(x+h) - f(x)}{h}\n", "$$\n", "Here, we'll take $h$ to be a single adjacent element" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "dx = x[1] - x[0]\n", "dfdx = (f[1:] - f[:-1])/dx" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "dfdx" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.3" } }, "nbformat": 4, "nbformat_minor": 1 }