{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "##Numpy\n", "\n", "_prepared by: Cindee Madison \n", "Thanks to: Ariel Rokem, Matt Davis, Justin Kitzes, Katy Huff, Matthew Terry, Scipy Tutorial\n", "\n", "Link to [master](http://swcarpentry.github.io/2014-04-14-wise/advanced/python/Numpy-master.ipynb) with answers\n", "\n", "\n", "Additional Resources\n", "\n", " * http://wiki.scipy.org/Tentative_NumPy_Tutorial\n", " * http://docs.scipy.org/doc/numpy/reference/\n", " * http://scipy-lectures.github.io/intro/numpy/index.html\n", " * http://wiki.scipy.org/NumPy_for_Matlab_Users\n", " * http://nbviewer.ipython.org/\n", "\n", "\n", "\n", "NumPy is a Python package implementing efficient collections of specific types of data (generally numerical), similar to the standard array\n", "module (but with many more features). NumPy arrays differ from lists and tuples in that the data is contiguous in memory. A Python **list**, \n", "```[0, 1, 2]```, in contrast, is actually an array of pointers to Python objects representing each number. This allows NumPy arrays to be\n", "considerably faster for numerical operations than Python lists/tuples.\n", "\n", "**Numpy** provides\n", "\n", "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", " \n", "The **Numpy** Library contains functions and things\n", "\n", "```python\n", " np.sqrt(64) #this is a function\n", " np.pi #this is variable, not a function\n", " np.sin( np.pi ) #a variable passed to a function\n", "```\n", "\n" ] }, { "cell_type": "code", "collapsed": true, "input": [ "# import library, standard convention\n", "import numpy as np" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": true, "input": [ "# To see what's in a package, type the name, a period, then hit tab\n", "#np?\n", "#np.\n", "np.pi?" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "# Some examples of numpy functions and \"things\":\n", "print(np.sqrt(4))\n", "print(np.pi) # Not a function, just a variable\n", "print(np.sin(np.pi)) # A function on a variable :) " ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2.0\n", "3.14159265359\n", "1.22464679915e-16\n" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Numpy arrays (ndarrays)\n", "\n", "Creating a NumPy array is as simple as passing a sequence to numpy.array:\n", " \n", "Numpy arrays are collections of things, all of which must be the same type, that work\n", "similarly to lists (as we've described them so far). The most important are:\n", "\n", "1. You can easily perform elementwise operations (and matrix algebra) on arrays\n", "1. Arrays can be n-dimensional\n", "1. Arrays must be pre-allocated (ie, there is no equivalent to append)\n", "\n", "Arrays can be created from existing collections such as lists, or instantiated \"from scratch\" in a \n", "few useful ways." ] }, { "cell_type": "code", "collapsed": false, "input": [ "arr1 = np.array([1, 2.3, 4]) \n", "print(type(arr1))\n", "print(arr1.dtype)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "float64\n" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "strarr = np.array([x for x in 'hello'])\n", "strarr.dtype" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 8, "text": [ "dtype('S1')" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "[x for x in 'hello']" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 11, "text": [ "['h', 'e', 'l', 'l', 'o']" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "strarr" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 10, "text": [ "array(['h', 'e', 'l', 'l', 'o'], \n", " dtype='|S1')" ] } ], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also explicitly specify the data-type if the automatically-chosen one would be unsuitable." ] }, { "cell_type": "code", "collapsed": false, "input": [ "arr2 = np.array([1, 2.56, 4], dtype=int) \n", "print(type(arr2))\n", "print(arr2.dtype)\n", "print arr2" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "int64\n", "[1 2 4]\n" ] } ], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you might expect, creating a NumPy array this way can be slow, since it must manually convert each element of a list into its equivalent C type (int objects become C ints, etc). There are many other ways to create NumPy arrays, such as\n", "\n", "* `np.identity` \n", "* `np.zeros` \n", "* `np.zeros_like`\n", "\n", "or by manually specifying the dimensions and type of the array with the low-level creation function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "arr3 = np.ndarray((2, 3, 4), dtype=complex) # Notice : `ndarray`, not `array`!\n", "print(type(arr3))\n", "\n", "\n", "## what are the values in arr3??" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n" ] } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": false, "input": [ "arr3" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 14, "text": [ "array([[[ 0.00000000e+000 +0.00000000e+000j,\n", " 4.44659081e-322 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j],\n", " [ 0.00000000e+000 +2.16695872e-314j,\n", " 2.16695872e-314 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j],\n", " [ 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j]],\n", "\n", " [[ 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j],\n", " [ 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j],\n", " [ 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j,\n", " 0.00000000e+000 +0.00000000e+000j]]])" ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Arrays have a `.shape` attribute, which stores the dimensions of the array as a tuple:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(arr3.shape)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For many of the examples below, we will be using `np.arange` which, similar to the Python built-in function `range`, returns a NumPy array\n", "of integers from 0 to N-1, inclusive. Like `range`, you can also specify a starting value and a step:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "arr4 = np.arange(2, 5)\n", "print(arr4)\n", "arr5 = np.arange(1, 5, 2)\n", "print(arr5)\n", "arr6 = np.arange(2, 10, 2)\n", "print arr6" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[2 3 4]\n", "[1 3]\n", "[2 4 6 8]\n" ] } ], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "np.arange(10)\n", "np.arange?" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise : Create an Array\n", "\n", "Create an array with values ranging from 0 to 10, in increments of 0.5. \n", "\n", "Reminder: get help by typing `np.arange?`, `np.ndarray?`, `np.array?`, etc. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "np.arange(0, 10.5, .5)\n", "\n" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 26, "text": [ "array([ 0. , 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. ,\n", " 4.5, 5. , 5.5, 6. , 6.5, 7. , 7.5, 8. , 8.5,\n", " 9. , 9.5, 10. ])" ] } ], "prompt_number": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arithmetic with arrays\n", "\n", "Since numpy exists to perform efficient numerical operations in Python, arrays have all the usual arithmetic operations available to them. These operations are performed element-wise (i.e. the same operation is performed independently on each element of the array)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(5)\n", "B = np.arange(5, 10)\n", "\n", "print 'A is ', A\n", "print 'B is ', B\n", "print (A+B)\n", "\n", "print(B-A)\n", "\n", "print(A*B)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "A is [0 1 2 3 4]\n", "B is [5 6 7 8 9]\n", "[ 5 7 9 11 13]\n", "[5 5 5 5 5]\n", "[ 0 6 14 24 36]\n" ] } ], "prompt_number": 31 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What would happen if A and B did not have the same `shape`?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A_10 = np.ones(10)\n", "B_5 = np.zeros(5)\n", "print A_10, B_5\n", "A_10 + B_5" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "ValueError", "evalue": "operands could not be broadcast together with shapes (10) (5) ", "output_type": "pyerr", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0mB_5\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mprint\u001b[0m \u001b[0mA_10\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mB_5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0mA_10\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0mB_5\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: operands could not be broadcast together with shapes (10) (5) " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.] [ 0. 0. 0. 0. 0.]\n" ] } ], "prompt_number": 33 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Arithmetic with scalars:\n", "In addition, if one of the arguments is a scalar, that value will be applied to **all** the elements of the array." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(5)\n", "A+10\n", "2*A\n", "A**2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 37, "text": [ "array([ 0, 1, 4, 9, 16])" ] } ], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Linear algebra with arrays\n", "You can use arrays as vectors and matrices in linear algebra operations\n", "\n", "Specifically, you can perform matrix/vector multiplication between arrays, by using the `.dot` method, or the `np.dot` function:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A, B\n", "print A.dot(B)\n", "print np.dot(A, B)\n", "A.shape" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "80\n", "80\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 42, "text": [ "(5,)" ] } ], "prompt_number": 42 }, { "cell_type": "code", "collapsed": false, "input": [ "big_a = np.ones((2,5))\n", "print big_a.shape\n", "big_a" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "(2, 5)\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 44, "text": [ "array([[ 1., 1., 1., 1., 1.],\n", " [ 1., 1., 1., 1., 1.]])" ] } ], "prompt_number": 44 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: *This is like the '`*`' operator in Matlab*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise : \n", " \n", "http://en.wikipedia.org/wiki/Dot_product\n", " \n", "1. Given two vectors in 2-space:\n", " \n", " `a = [1,2]`\n", " \n", " `b = [4,5]`\n", "\n", " Find the angle between these vectors. \n", "1. The rotation matrix of $\\theta$ angle is a matrix with elements: \n", " \n", " [[cos($\\theta$), -sin($\\theta$], \n", " \n", " [sin($\\theta$, cos($\\theta$)]]\n", " \n", " Create a function that takes two 2D-vectors and creates the rotation matrix between them.\n", "1. For the vector `c=[7,8]`, find a vector `d` that has the same rotation as `b` has relative to `a`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "http://en.wikipedia.org/wiki/Dot_product\n", "\n", "We can use a dot product to help us find theta $$\\theta$$\n", "\n", "$$\\mathbf A\\cdot\\mathbf B = \\|\\mathbf A\\|\\,\\|\\mathbf B\\|\\cos\\theta$$\n", "\n", "\n", "$$\\|\\mathbf{p}\\| = \\sqrt{p_1^2+p_2^2+\\cdots +p_n^2} = \\sqrt{\\mathbf{p}\\cdot\\mathbf{p}}$$\n", "Where \n", "$$\\sqrt{\\mathbf{p}\\cdot\\mathbf{p}}$$\n", "is the square root of the dot product\n", "\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.array([1,2])\n", "b = np.array([4,5])\n", "\n", "\n", "def angle_between_vectors(a,b):\n", " \"\"\"\n", " find the angle between two vectors\n", " \"\"\"\n", " norm_a = np.sqrt(a.dot(a))\n", " norm_b = np.sqrt(b.dot(b))\n", " ab_dot = a.dot(b)\n", " theta = np.arccos(ab_dot / (norm_a * norm_b))\n", " return theta\n", "\n", "theta = angle_between_vectors(a,b)\n", "print theta\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "## create rotation matrix\n", "def rotation_matrix(theta):\n", " \"\"\" create a rotation matrix given theta\"\"\"\n", " rot = np.array([\n", " [np.cos(theta), -np.sin(theta)],\n", " [np.sin(theta), np.cos(theta)],\n", " ])\n", " return rot\n", "\n", "ab_rot = rotation_matrix(theta)\n", "print ab_rot\n", " " ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "## we know the angle between a and b\n", "## find a vector rotated by the same amount relative to c = [7,8,9], \n", "c = np.array([7,8])\n", "new = c.dot(ab_rot)\n", "print angle_between_vectors(c,new)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Boolean operators work on arrays too, and they return boolean arrays\n", "Much like the basic arithmetic operations we discussed above, comparison operations are perfomed element-wise. That is, rather than returning a\n", "single boolean, comparison operators compare each element in both arrays pairwise, and return an `array` of booleans (if the sizes of the input\n", "arrays are incompatible, the comparison will simply return False). For example:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "arr1 = np.array([1, 2, 3, 4, 5])\n", "arr2 = np.array([1, 1, 3, 3, 5])\n", "print(arr1 == arr2)\n", "c = (arr1 == arr2)\n", "print c.dtype\n", "print c.sum()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ True False True False True]\n", "bool\n", "3\n" ] } ], "prompt_number": 48 }, { "cell_type": "code", "collapsed": false, "input": [ "arr1[c]\n", "\n", "for mybool, item in zip(c, arr1):\n", " if mybool:\n", " print item **2" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "1\n", "9\n", "25\n" ] } ], "prompt_number": 51 }, { "cell_type": "code", "collapsed": false, "input": [ "arr2[c]**2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 52, "text": [ "array([ 1, 9, 25])" ] } ], "prompt_number": 52 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note: You can use the methods `.any()` and `.all()` or the functions `np.any` and `np.all` to return a single boolean indicating whether any or all values in the array are `True`, respectively.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print(np.all(c))\n", "print(c.all())\n", "print(c.any())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "False\n", "False\n", "True\n" ] } ], "prompt_number": 50 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Indexing arrays\n", "\n", "In addition to the usual methods of indexing lists with an integer (or with a series of colon-separated integers for a slice), numpy allows you\n", "to index arrays in a wide variety of different ways for more advanced operations.\n", "\n", "First, the simple way:\n", "\n", "Note: python indexes from zero" ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = np.array([1,2,3])\n", "print a[0:2]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1 2]\n" ] } ], "prompt_number": 53 }, { "cell_type": "code", "collapsed": false, "input": [ "a[1:2]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 57, "text": [ "array([2])" ] } ], "prompt_number": 57 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### What happens if the array has more than one dimension? " ] }, { "cell_type": "code", "collapsed": false, "input": [ "c = np.random.rand(3,3)\n", "print(c)\n", "#print(c[1:,0:2])\n", "#print a\n", "c[0,:] = a\n", "print\n", "\n", "\n", "c[0,:] = 42\n", "print(c)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[ 0.80833693 0.83243262 0.26534231]\n", " [ 0.75869528 0.31479564 0.06134746]\n", " [ 0.77592561 0.24624831 0.03440165]]\n", "\n", "[[ 4.20000000e+01 4.20000000e+01 4.20000000e+01]\n", " [ 7.58695276e-01 3.14795638e-01 6.13474585e-02]\n", " [ 7.75925606e-01 2.46248308e-01 3.44016533e-02]]\n" ] } ], "prompt_number": 66 }, { "cell_type": "code", "collapsed": false, "input": [ "myvals = np.ones(100) * 13 + np.random.random(100)\n", "print myvals" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 13.59114593 13.34001837 13.5375499 13.00451878 13.28052895\n", " 13.94806292 13.17553366 13.67686981 13.02973211 13.91452831\n", " 13.47677767 13.93323565 13.9551556 13.56607387 13.14314234\n", " 13.65010953 13.17455852 13.95296247 13.6675259 13.24268106\n", " 13.30771672 13.10878015 13.17385343 13.45145132 13.63363837\n", " 13.79471584 13.11998411 13.56198842 13.85606593 13.23624152\n", " 13.19706126 13.25253607 13.08575879 13.79461907 13.78047991\n", " 13.08693021 13.59714173 13.27073197 13.51291035 13.8937349\n", " 13.3952584 13.822228 13.30955901 13.51256604 13.70593058\n", " 13.3076226 13.17250251 13.61906959 13.83212702 13.35391282\n", " 13.97660988 13.74179028 13.08792259 13.39055293 13.44074272\n", " 13.12399919 13.91794852 13.41646663 13.53261444 13.16821828\n", " 13.06599806 13.26396216 13.42179522 13.02195477 13.24126517\n", " 13.80587748 13.62336911 13.59498972 13.13110852 13.57466704\n", " 13.91718828 13.27493337 13.39197814 13.26310546 13.25496674\n", " 13.63496534 13.0480124 13.35018566 13.76447972 13.5514787\n", " 13.71308711 13.60618318 13.6336942 13.92933969 13.37967773\n", " 13.51699195 13.166105 13.59111672 13.19483767 13.21579675\n", " 13.51226399 13.9978466 13.40086006 13.53810426 13.78326947\n", " 13.59867458 13.56798128 13.43876532 13.42391088 13.52500084]\n" ] } ], "prompt_number": 70 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise\n", "We can manipulate the shape of an array as follows: \n", "\n", " `A = np.arange(16).reshape(4, 4)`\n", " \n", "Or even:\n", "\n", " `A = np.reshape(numpy.arange(16), (4, 4))`\n", " \n", "Using what we've learned about slicing and indexing,\n", "\n", "1. Create A, index the array to get the upper-left quarter\n", "\n", "2. create a function \n", "\n", " * that takes an integer as input \n", " * creates a square n-by-n array with integers from `0` to `n**2-1` (like `A`) \n", " * prints just the upper-left quarter of the array\n", "\n", "For example, for A, the desired output would be: \n", " \n", " array([[2, 3],\n", " [6, 7]])" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# create A and slice to get upper corner\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# create code that generates a square array, and outputs upper 4th quarter\n", "\n", "\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Arrays can also be indexed with other arrays\n", "\n", "Arrays can be indexed with other arrays, using either an array of indices, or an array of booleans of the same length. In the former case, numpy returns a view of the data in the specified indices as a new array. In the latter, numpy returns a view of the array with only the elements where the index array is True. (We'll discuss the difference between views and copies in a moment.) This makes normally-tedious operations like clamping extremely simple.\n", "\n", "Indexing with an array of indices:\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(5, 10)\n", "print(A)\n", "print(A[[0, 2, 3]])\n", "A[[0, 2, 3]] = 0\n", "print(A)\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indexing with a boolean array:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "random = np.random\n", "A = np.array([random.randint(0, 10) for i in range(10)]) # Check out the list comprehension!\n", "print 'A', (A)\n", "A[A>5] = 5\n", "print(A)\n", "\n", "stuff_lessthan5 = A[A<5]\n", "print stuff_lessthan5" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "A [6 7 9 0 3 9 4 4 2 7]\n", "[5 5 5 0 3 5 4 4 2 5]\n", "[0 3 4 4 2]\n" ] } ], "prompt_number": 75 }, { "cell_type": "markdown", "metadata": {}, "source": [ "A few more examples:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "b = np.array([4,5,6])\n", "print (a)\n", "print (b)\n", "print (a > 2)\n", "print (a[a > 2])\n", "print (b[a > 2])\n", "b[a == 3] = 77\n", "print(b)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# There are handy ways to make arrays full of ones and zeros\n", "print(np.zeros(5))\n", "print np.ones(5)\n", "print np.identity(5), '\\n'" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Numpy 'gotchas'\n", "\n", "### Multiplication and Addition\n", "\n", "As you may have noticed above, since NumPy arrays are modeled more closely after vectors and matrices, multiplying by a scalar will multiply each element of the array, whereas multiplying a list by a scalar will repeat that list N times." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(5)*2\n", "print(A) \n", "B = range(5)*2\n", "print(B)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, when adding two numpy arrays together, we get the vector sum back, whereas when adding two lists together, we get the concatenation back." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(5) + np.arange(5)\n", "print(A)\n", "B =range(5) + range(5)\n", "print(B)" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Views vs. Copies\n", "\n", "In order to be as efficient as possible, numpy uses \"views\" instead of copies wherever possible. That is, numpy arrays derived from another base array generally refer to the ''exact same data'' as the base array. The consequence of this is that modification of these derived arrays will also modify the base array. The result of an array indexed by an array of indices is a ''copy'', but an array indexed by an array of booleans is a ''view''. \n", "\n", "Specifically, slices of arrays are always views, unlike slices of lists or tuples, which are always copies." ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(5)\n", "B = A[0:1]\n", "B[0] = 42\n", "print(A)\n", "\"\"\"\n", "A = range(5)\n", "B = A[0:1]\n", "B[0] = 42\n", "print(A)\n", "\"\"\"\n", " \n", " " ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[42 1 2 3 4]\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 76, "text": [ "'\\nA = range(5)\\nB = A[0:1]\\nB[0] = 42\\nprint(A)\\n'" ] } ], "prompt_number": 76 }, { "cell_type": "code", "collapsed": false, "input": [ "B = A[:2].copy()\n", "print B" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[42 1]\n" ] } ], "prompt_number": 80 }, { "cell_type": "code", "collapsed": false, "input": [ "B[0] = 0\n", "print A" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[42 1 2 3 4]\n" ] } ], "prompt_number": 81 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Exercise : Copy a numpy array\n", "\n", "Figure out how to create a copy of a numpy array. Remember: since numpy slices are views, you can't use the trick you'd use for Python lists,\n", "i.e. copy = list[:]." ] }, { "cell_type": "code", "collapsed": false, "input": [ "## create an array of 10 random numbers\n", "## np.random.random?\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "# create a view and change the first element in the view\n", "## what is the value in the original\n" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": false, "input": [ "## now create a copy" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mathematics with numpy\n", "\n", "Being designed for scientific computing, numpy also contains a host of common mathematical functions, including linear algebra functions, fast\n", "Fourier transforms, and probability/statistics functions. While there isn't space to go over ''all'' of these in detail, we will provide an overview of the most common/essential of these." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For >2-dimensional arrays, there are some other common matrix operations that can be conducted:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(16).reshape(4, 4)\n", "print(A)\n", "print(A.T) # transpose\n", "print(A.trace())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[ 0 1 2 3]\n", " [ 4 5 6 7]\n", " [ 8 9 10 11]\n", " [12 13 14 15]]\n", "[[ 0 4 8 12]\n", " [ 1 5 9 13]\n", " [ 2 6 10 14]\n", " [ 3 7 11 15]]\n", "30\n" ] } ], "prompt_number": 82 }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are many more methods like these available with NumPy arrays. Be sure to consult the numpy documentation before writing your own versions!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The `matrix` class \n", "\n", "So far, we've used two-dimensional arrays to represent matrix-like objects. However, numpy provides a specialized class for this. The `matrix` class is almost identical to a two-dimensional numpy array, but has a few changes to the interface to simplify common linear algebraic tasks. These are: \n", "\n", " * The * operator is performs matrix multiplication \n", " * The ** operator performs matrix exponentiation \n", " * The property .I (or the method .getI()) returns the matrix inverse \n", " * The property .H (or the method .getH()) returns the conjugate transpose\n", "\n", "### Example: Solving a System of Linear Equations" ] }, { "cell_type": "code", "collapsed": false, "input": [ "la = np.linalg\n", "A = np.matrix([[3, 2, -1], [2, -2, 4], [-1, .5, -1]])\n", "B = np.array([1, -2, 0])\n", "print(la.solve(A, B))" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Universal functions \n", "\n", "Universal functions (also called ufuncs) are high-speed, element-wise operations on NumPy arrays. They are, in essence, what allows you to operate on NumPy arrays efficiently. There are a large number of universal functions available covering most of the basic operations that get performed on data, like addition, subtraction, logarithms, and so on. Calling a ufunc is a simple matter:\n", "\n", " " ] }, { "cell_type": "code", "collapsed": false, "input": [ "A = np.arange(1,10)\n", "print(np.log10(A))" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to basic operation like above, ufuncs that take two input arrays and return an output array can be used in more advanced ways.\n", "\n", "### Exercise : Elementwise Operations\n", "\n", "Use %timeit magic to check speed\n", "\n", "Using ufuncs, calculate the log of each element in the following array, compare speed to list operation:\n", " \n", " [8.1, 1.6, 0.9, 4.3, 7.0, 7.3, 4.7, 8.2, 7.2, 3.0,\n", " 1.4, 9.8, 5.7, 0.7, 8.7, 4.6, 8.8, 0.9, 4.4, 4.4]\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# create list, and array\n", "## calculate log on all elements in list (list comprehension)\n", "## calculate log on all elements in array\n", "## use timeit to compare processing time\n" ], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }