{ "metadata": { "name": "", "signature": "sha256:657bed7c3c8b639f44ae835b7a330e9b8c7ab94e7e8e6cf910f92f3438b95943" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction to / review of Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a full version of these notes with the examples filled in click [here](http://nbviewer.ipython.org/github/abostroem/2015-01-03-aas/blob/gh-pages/intermediate/python-review/python-full.ipynb). This is useful if you fall behind or want to refer back to these notes later." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Why Python?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Clean and powerful language designed by people who highly value elegance and readability.\n", "* Strong set of 3rd party analysis tools that are professionally and actively developed.\n", " * In particular a lot of momentum behind use of Python to develop scientific tools over the last decade:\n", " If you analyze data from Chandra, LOFAR, Fermi, Herschel, HST, JWST, ALMA, EVLA (etc etc) you will likely end up using Python even if you didn\u2019t intend it. So learning to use Python for for Astronomy data analysis has a good chance of paying off.\n", "* Interfaces well with existing C, C++, and FORTRAN libraries, providing access to existing libraries, such as robust numerical libraries like BLAS, ATLAS, etc. but with an easier to use interface.\n", " * Easier then to write numerical code, while also interacting with databases, using data from the web, visualization,\n", " and other such tasks that a higher-level language makes easier, all without leaving Python.\n", "* Very active developer community.\n", "* Free as in open source, and \"free as in beer\". Anyone can run Python on almost any platform for free--neither you nor your collaborators will need to worry about having the proper licenses to run software written in Python (unless of course the software itself is proprietary, though that is uncommon).\n", "\n", "\n", "**Why not?**\n", "\n", "* Switching from a familiar analysis environment is NOT FREE (hours \\* dollars/hour \\* overhead_rate)\n", " * \u201cUgh, I could do this so much faster the old way.\u201d\n", " * \u201cI can't find the functions I need to do [insert favorite IDL function].\u201d\n", " * \u201cStupid Python, why isn\u2019t this working?!\u201d\n", " * \u201cThese plots look ugly.\u201d\n", " \n", "However, Python has been actively used in the astronomy community for 10+ years, and has even driven some of the development of Python." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Table of Contents" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* [1. Individual things](#1.-Individual-things)\n", "* [2. Commands that operate on things](#2.-Commands-that-operate-on-things)\n", " * [EXERCISE 1 - Introducing logistic growth](#EXERCISE-1---Introducing-logistic-growth)\n", "* [3. Collections of things](#3.-Collections-of-things)\n", " * [EXERCISE 2 - Storing population size in a list](#EXERCISE-2---Storing-population-size-in-a-list)\n", " * [EXERCISE 3 - Storing data in arrays](#EXERCISE-3---Storing-data-in-arrays)\n", "* [4. Repeating yourself](#4.-Repeating-yourself)\n", " * [EXERCISE 4 - Using loops to repeat calculations](#EXERCISE-4---Using-loops-to-repeat-calculations)\n", "* [5. Making choices](#5.-Making-choices)\n", " * [EXERCISE 5 - Making the model stochastic with an if statement](#EXERCISE-5---Making-the-model-stochastic-with-an-if-statement)\n", "* [6. Creating chunks with functions and modules](#6.-Creating-chunks-with-functions-and-modules)\n", " * [EXERCISE 6 - Creating a logistic growth function](#EXERCISE-6---Creating-a-logistic-growth-function)\n", " * [EXERCISE 7 - Putting the growth function(s) in a module](#EXERCISE-7---Putting-the-growth-functions-in-a-module)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "1. Individual things" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The most basic component of any programming language are \"things\", also called objects.\n", "\n", "The most common basic \"things\" in Python are integers, floats, strings, booleans, and\n", "some special objects of various types. We'll meet many of these as we go through the lesson." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__TIP:__ To run the code in a cell quickly, press Ctrl-Enter." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__TIP:__ To quickly create a new cell below an existing one, hit the ESC key to go into the notebook's \"command mode\" and then hit the 'b' key.\n", "Other shortcuts for making, deleting, and moving cells are in the menubar at the top of the\n", "screen." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# A thing\n", "2" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 1, "text": [ "2" ] } ], "prompt_number": 1 }, { "cell_type": "code", "collapsed": true, "input": [ "# Use print to show multiple things in the same cell\n", "# Note that you can use single or double quotes for strings\n", "print 2\n", "print \"hello\"" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2\n", "hello\n" ] } ], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "print 'hello'" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hello\n" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "print 'hello \"AAS\"'" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hello \"AAS\"\n" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": true, "input": [ "# Things can be stored as variables\n", "a = 2\n", "b = 'hello'\n", "c = True\n", "print a, b, c" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2 hello True\n" ] } ], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "a = b" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "print a" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hello\n" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": true, "input": [ "# The type function tells us the type of thing we have\n", "print type(a)\n", "print type(b)\n", "print type(c)\n", "print type(3)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "\n", "\n", "\n" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "[^Back to top](#Table-of-Contents)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "2. Commands that operate on things" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just storing data in variables isn't much use to us. Right away, we'd like to start performing\n", "operations and manipulations on data and variables.\n", "\n", "There are three very common means of performing an operation on a thing." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "2.1 Use an operator" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "All of the basic math operators work like you think they should for numbers. They can also\n", "do some useful operations on other things, like strings. There are also boolean operators that\n", "compare quantities and give back a `bool` variable as a result." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# Standard math operators work as expected in numerical expressions\n", "print 2 + 3\n", "print 2 * 3\n", "print 2 ** 3" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "5\n", "6\n", "8\n" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "# We can also assign numbers to named variables for use in expressions\n", "a = 2\n", "b = 3\n", "print a + b\n", "print a * b\n", "print a ** b" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "5\n", "6\n", "8\n" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": true, "input": [ "# But be careful with integer division\n", "# Also watch out for exponentiation - you want **, not ^\n", "print 2/3\n", "print 5//4\n", "print 2/3.0" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "0\n", "1\n", "0.666666666667\n" ] } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": true, "input": [ "# There are also operators for strings\n", "print 'hello' + ' world'\n", "print 'hello' * 3\n", "a = '1'\n", "b = 2\n", "print a * b" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hello world\n", "hellohellohello\n", "11\n" ] } ], "prompt_number": 16 }, { "cell_type": "code", "collapsed": true, "input": [ "# Boolean operators compare two things\n", "print 1 > 3\n", "print 3 == 3\n", "print (1 > 3) or (3 == 3)\n", "print (1 > 3) and (3 == 3)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "False\n", "True\n", "True\n", "False\n" ] } ], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "# This prints the \"Zen of Python\" which lists some of the principles\n", "# behind the design of Python itself, as well was (ideally) software\n", "# written in Python\n", "import this" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "The Zen of Python, by Tim Peters\n", "\n", "Beautiful is better than ugly.\n", "Explicit is better than implicit.\n", "Simple is better than complex.\n", "Complex is better than complicated.\n", "Flat is better than nested.\n", "Sparse is better than dense.\n", "Readability counts.\n", "Special cases aren't special enough to break the rules.\n", "Although practicality beats purity.\n", "Errors should never pass silently.\n", "Unless explicitly silenced.\n", "In the face of ambiguity, refuse the temptation to guess.\n", "There should be one-- and preferably only one --obvious way to do it.\n", "Although that way may not be obvious at first unless you're Dutch.\n", "Now is better than never.\n", "Although never is often better than *right* now.\n", "If the implementation is hard to explain, it's a bad idea.\n", "If the implementation is easy to explain, it may be a good idea.\n", "Namespaces are one honking great idea -- let's do more of those!\n" ] } ], "prompt_number": 24 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "2.2 Use a function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These will be very familiar to anyone who has programmed in any language, and work like you\n", "would expect." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# There are thousands of functions that operate on things\n", "print type(3)\n", "print len('hello')\n", "print round(3.3)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "5\n", "3.0\n" ] } ], "prompt_number": 25 }, { "cell_type": "markdown", "metadata": {}, "source": [ "__TIP:__ To find out what a function does, you can type it's name and then a question mark to\n", "get a pop up help window. Or, to see what arguments it takes, you can type its name, an open\n", "parenthesis, and hit tab." ] }, { "cell_type": "code", "collapsed": true, "input": [ "round?\n", "round()" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ "__TIP:__ Many useful functions are not in the Python built in library, but are in external\n", "scientific packages. These need to be imported into your Python notebook (or program) before\n", "they can be used. Probably the most important of these are numpy and matplotlib." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# Many useful functions are in external packages\n", "# Let's meet numpy\n", "import numpy as np\n", "np.array" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 4, "text": [ "" ] } ], "prompt_number": 4 }, { "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.asscalar" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 30 }, { "cell_type": "code", "collapsed": true, "input": [ "# Some examples of numpy functions and \"things\"\n", "print np.sqrt(4)\n", "print np.pi\n", "print np.sin(np.pi)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2.0\n", "3.14159265359\n", "1.22464679915e-16\n" ] } ], "prompt_number": 32 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "2.3 Use a method" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Before we get any farther into the Python language, we have to say a word about \"objects\". We\n", "will not be teaching object oriented programming in this workshop, but you will encounter objects\n", "throughout Python (in fact, even seemingly simple things like ints and strings are actually\n", "objects in Python).\n", "\n", "In the simplest terms, you can think of an object as a small bundled \"thing\" that contains within\n", "itself both data and functions that operate on that data. For example, strings in Python are\n", "objects that contain a set of characters and also various functions that operate on the set of\n", "characters. When bundled in an object, these functions are called \"methods\".\n", "\n", "Instead of the \"normal\" `function(arguments)` syntax, methods are called using the\n", "syntax `variable.method(arguments)`." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# A string\n", "a = 'hello'\n", "print a.capitalize()\n", "print a.replace('l', 'x')\n", "print a.upper()\n", "len(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Hello\n", "hexxo\n", "HELLO\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 34, "text": [ "5" ] } ], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "# Note, most (finite) collections of things have a length that can\n", "# be found with the len() operator on that object (what is a string\n", "# a collection of?)\n", "len([1, 2, 3])" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 35, "text": [ "3" ] } ], "prompt_number": 35 }, { "cell_type": "code", "collapsed": false, "input": [ "# Scalar values like individual numbers do not have a length\n", "len(2.3)" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "object of type 'float' has no len()", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m2.3\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: object of type 'float' has no len()" ] } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": true, "input": [ "# Objects have bundled methods" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "EXERCISE 1 - Introducing logistic growth" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Throughout this lesson, we will successively build towards a program that will calculate the\n", "logistic growth of a population of bacteria in a petri dish (or bears in the woods, if you\n", "prefer). The exercises will build on each other - if at any time you get behind, you can open the\n", "notebook _python-full_ to review answers to the previous exercises and catch up.\n", "\n", "As a reminder, a commonly used discrete time equation for logistic population growth is\n", "\n", "$$\n", "n(t+1) = n(t) + r n(t) [1 - n(t) / K]\n", "$$\n", "\n", "where $ n(t)$ is the population size at time $ t $, $ r $ is the net per capita growth rate, and $ K $ is the\n", "carrying capacity of the dish/woods.\n", "\n", "To get started, write Python expressions that do the following:\n", "\n", "1. Create variables for `r`, `K`, and `n0`, setting these equal to 0.6, 100, and 10, respectively.\n", "1. Create the variable `n1` and calculate its value. Do the same for `n2`.\n", "1. Check the type of `n2` - what is it?\n", "1. Modify your calculations for `n1` and `n2` so that these values are rounded to the nearest\n", "integer.\n", "\n", "__Bonus__\n", "\n", "1. Test whether `n2` is larger than 20, and print out a line that says \"n2 more than 20: \"\n", "followed by the answer (either True or False).\n", "1. Figure out how to test whether `n2` is an integer (a mathematical integer, not necessarily\n", "whether it is an integer type) (HINT: look at the methods of `n2` by typing `n2.` and pressing\n", "tab.)" ] }, { "cell_type": "code", "collapsed": true, "input": [ "r = 0.6\n", "K = 100.0\n", "n0 = 10\n", "\n", "n1 = round(n0 + (r * n0) * (1 - n0 / K))\n", "n2 = round(n1 + (r * n1) * (1 - n1 / K))\n", "\n", "print n0, n1, n2\n", "print type(n2)\n", "\n", "print 'n2 more than 20:', n2 > 20\n", "print 'n2 is an integer', n2.is_integer()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "10 15.0 23.0\n", "\n", "n2 more than 20: True\n", "n2 is an integer True\n" ] } ], "prompt_number": 42 }, { "cell_type": "markdown", "metadata": {}, "source": [ "[^Back to top](#Table-of-Contents)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "3. Collections of things" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once the number of variables that you are interested in starts getting large, working with them\n", "all individually starts to get unwieldy. To help stay organized, we can use collections of things.\n", "\n", "Probably 99% of your work in scientific Python will use one of four types of collections:\n", "lists, tuples, dictionaries, and numpy arrays. We'll look quickly at each of these and what\n", "they can do for you." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "3.1 Lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists are probably the handiest and most flexible type of container. Lists are declared with\n", "square brackets `[]`. Individual elements of a list can be selected using the syntax `a[ind]`." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# Lists are created with square bracket syntax\n", "a = ['hi', 'hello', 'yo']\n", "print a\n", "print type(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "['hi', 'hello', 'yo']\n", "\n" ] } ], "prompt_number": 43 }, { "cell_type": "code", "collapsed": true, "input": [ "# Lists (and all collections) are also indexed with square brackets\n", "# NOTE: The first index is zero, not one\n", "print a[0]\n", "print a[1]\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hi\n", "hello\n" ] } ], "prompt_number": 44 }, { "cell_type": "code", "collapsed": false, "input": [ "# Indexing on a variable like `a` is exactly the same as if we were\n", "# directly indexing the object pointed to by that variable\n", "['hi', 'hello', 'yo'][0]" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 45, "text": [ "'hi'" ] } ], "prompt_number": 45 }, { "cell_type": "code", "collapsed": true, "input": [ "# Lists can be sliced by putting a colon between indexes\n", "# NOTE: The end value is not inclusive\n", "print a[0:2]\n", "print [a[0], a[1]]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "['hi', 'hello']\n", "['hi', 'hello']\n" ] } ], "prompt_number": 47 }, { "cell_type": "code", "collapsed": true, "input": [ "# You can leave off the start or end if desired\n", "print a[:2] # same as a[0:2]\n", "print a[2:]\n", "print a[0:0]\n", "print a[:]\n", "print a[:-1] # a[0:len(a)-2]\n", "print a[:-2]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "['hi', 'hello']\n", "['yo']\n", "[]\n", "['hi', 'hello', 'yo']\n", "['hi', 'hello']\n", "['hi']\n" ] } ], "prompt_number": 54 }, { "cell_type": "code", "collapsed": false, "input": [ "# Just remember that a[:] makes a *copy* of list" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": true, "input": [ "# Lists are objects, like everything else, and have methods such as append\n", "a.append('hiya')\n", "print a\n", "\n", "a.append([1, 2])\n", "print a\n", "\n", "a.append(20)\n", "print a" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "['hi', 'hello', 'yo', 'hiya', 'hiya', [1, 2], 'hiya', [1, 2], 20, 'hiya']\n", "['hi', 'hello', 'yo', 'hiya', 'hiya', [1, 2], 'hiya', [1, 2], 20, 'hiya', [1, 2]]\n", "['hi', 'hello', 'yo', 'hiya', 'hiya', [1, 2], 'hiya', [1, 2], 20, 'hiya', [1, 2], 20]\n" ] } ], "prompt_number": 58 }, { "cell_type": "code", "collapsed": false, "input": [ "# A very common use of lists is to create a range of integers\n", "# This is easy in Python using the built-in range function like\n", "# range(start, end); note that like the 'slice' notation the end value\n", "# is *not* inclusive\n", "print range(10)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "prompt_number": 60 }, { "cell_type": "markdown", "metadata": {}, "source": [ "__TIP:__ A 'gotcha' for some new Python users is that many collections, including lists,\n", "actually store pointers to data, not the data itself. This means that you need to be careful with\n", "writing things `b = a` and then changing `a`, since this will also change `b`. Have a look at the \n", "`copy` module if you want to make copies of variables." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "EXERCISE 2 - Storing population size in a list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Copy your code from Exercise 1 into the box below, and do the following:\n", "\n", "1. Modify your code so that the values of `n0`, `n1`, `n2`, and `n3` are stored in a list and not as\n", "separate individual variables. HINT: You can start off by declaring an empty list using the syntax\n", "`n = []`, and then append each new calculated value of `nt` to the list.\n", "1. Get the first and last values in the list, calculate their ratio, and print out \"Grew by a factor of \"\n", "followed by the result.\n", "\n", "__Bonus__\n", "\n", "1. Extract the last value in two different ways: first, by using the index for\n", "the last item in the list, and second, presuming that you do not know how long the list is.\n", "1. Change the values of `r` and `K` to make sure that your cell still runs correctly and gives\n", "reasonable answers." ] }, { "cell_type": "code", "collapsed": true, "input": [ "######################################\n", "# This code deletes our old variables\n", "try: del n0, n1, n2, r, K\n", "except: pass\n", "######################################\n", "r = 0.6\n", "K = 100.0\n", "n = []\n", "n.append(10)\n", "\n", "n.append(round(n[0] + (r * n[0]) * (1 - n[0] / K)))\n", "n.append(round(n[1] + (r * n[1]) * (1 - n[1] / K)))\n", "n.append(round(n[2] + (r * n[2]) * (1 - n[2] / K)))\n", "\n", "print n\n", "print 'Grew by a factor of', n[-1]/n[0]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[10, 15.0, 23.0, 34.0]\n", "Grew by a factor of 3.4\n" ] } ], "prompt_number": 62 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "3.2 Dictionaries" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dictionaries are the collection to use when you want to store and retrieve things by their names\n", "(or some other kind of key) instead of by their position in the collection. A good example is a set\n", "of model parameters, each of which has a name and a value. Dictionaries are declared using {}." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# Make a dictionary of model parameters\n", "params = {'n0': 10, 'r': 0.5}\n", "print params\n", "print params['r']" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "{'n0': 10, 'r': 0.5}\n", "0.5\n" ] } ], "prompt_number": 63 }, { "cell_type": "code", "collapsed": true, "input": [ "params['K'] = 200" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 64 }, { "cell_type": "code", "collapsed": true, "input": [ "# All the variables you define are actually saved in a special\n", "# dictionary internal to Python that can you can access using the built-in\n", "# locals() function:\n", "\n", "K = 200\n", "locals()['K']" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 66, "text": [ "200" ] } ], "prompt_number": 66 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "3.3 Tuples" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We won't say a whole lot about tuples except to mention that they basically work just like lists, with\n", "two major exceptions:\n", "\n", "1. You declare tuples using `()` instead of `[]`\n", "1. Once you make a tuple, you can't change what's in it\n", "\n", "You'll see tuples come up throughout the Python language, and over time you'll develop a feel for when\n", "to use them. In general, they're often used instead of lists to group items when the position in the\n", "collection is critical to understanding the item's meaning, such as `(x,y)`, and when you want to make\n", "sure that you don't accidentally modify any of the items later." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "3.4 Numpy arrays (ndarrays)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Even though numpy arrays (often written as ndarrays, for n-dimensional arrays) are not part of the\n", "core Python libraries, they are so useful in scientific Python that we'll include them here in the \n", "core lesson. 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.\n", "\n", "When getting started with scientific Python, you will probably want to try to use ndarrays whenever\n", "possible, saving the other types of collections for those cases when you have a specific reason to use\n", "them." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Python lists don't support numerical operations (Python has no way of ensuring\n", "# that all elements of the list are a numeric type, since lists can contain a mixture\n", "# of any object types)\n", "a = [1, 2, 3]\n", "a + 4" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "can only concatenate list (not \"int\") to list", "output_type": "pyerr", "traceback": [ "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m\n\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0ma\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m3\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0ma\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: can only concatenate list (not \"int\") to list" ] } ], "prompt_number": 67 }, { "cell_type": "code", "collapsed": false, "input": [ "# (Surprisingly, multiplication of a list by a number does work, but it doesn't do what\n", "# we might want to do with numerical data...)\n", "a * 4" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 68, "text": [ "[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]" ] } ], "prompt_number": 68 }, { "cell_type": "code", "collapsed": true, "input": [ "# Make an array from a list\n", "import numpy as np\n", "\n", "alist = [2, 3, 4]\n", "blist = [5, 6, 7]\n", "\n", "a = np.array(alist)\n", "b = np.array(blist)\n", "\n", "print a\n", "print b" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[2 3 4]\n", "[5 6 7]\n" ] } ], "prompt_number": 69 }, { "cell_type": "code", "collapsed": true, "input": [ "# Do arithmetic on arrays\n", "print a + 4\n", "print a ** 2\n", "print np.sin(a)\n", "print a * b\n", "\n", "# Broadcasting in Numpy\n", "\n", "print np.dot(a, b)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[6 7 8]\n", "[ 4 9 16]\n", "[ 0.90929743 0.14112001 -0.7568025 ]\n", "[10 18 28]\n", "56\n" ] } ], "prompt_number": 75 }, { "cell_type": "code", "collapsed": true, "input": [ "# Boolean operators work on arrays too, and they return boolean arrays\n", "print a\n", "print a > 2\n", "print a[a > 2]\n", "\n", "c = a > 2\n", "type(c)\n", "print c.dtype\n", "print a.dtype\n", "\n", "f = np.array([1.0, 2.0, 3.0])\n", "print(f.dtype)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[2 3 4]\n", "[False True True]\n", "[3 4]\n", "bool\n", "int64\n", "float64\n" ] } ], "prompt_number": 82 }, { "cell_type": "code", "collapsed": true, "input": [ "# Indexing arrays\n", "print a[0]\n", "print a[0:2]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "2\n", "[2 3]\n" ] } ], "prompt_number": 86 }, { "cell_type": "code", "collapsed": false, "input": [ "c = np.random.rand(3, 3)\n", "print c\n", "c[1][1] = 42\n", "print c\n", "c[1]\n", "# c[1][1] # don't use this, use this:\n", "c[1, 1]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[[ 0.23976327 0.96496104 0.42249143]\n", " [ 0.09107841 0.74538248 0.34056617]\n", " [ 0.44997111 0.84155608 0.29793788]]\n", "[[ 0.23976327 0.96496104 0.42249143]\n", " [ 0.09107841 42. 0.34056617]\n", " [ 0.44997111 0.84155608 0.29793788]]\n" ] }, { "metadata": {}, "output_type": "pyout", "prompt_number": 93, "text": [ "42.0" ] } ], "prompt_number": 93 }, { "cell_type": "code", "collapsed": true, "input": [ "# Arrays can also be indexed with other boolean arrays\n", "print a > 2\n", "print a[a > 2]\n", "\n", "mask = a > 2\n", "print a[mask]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[False True True]\n", "[3 4]\n", "[3 4]\n" ] } ], "prompt_number": 96 }, { "cell_type": "code", "collapsed": true, "input": [ "# ndarrays have attributes in addition to methods\n", "print a.dtype\n", "print a.prod()\n", "print a.sum()\n", "print a.mean()\n", "print a.shape\n", "\n", "print c.shape" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "int64\n", "24\n", "9\n", "3.0\n", "(3,)\n", "(3, 3)\n" ] } ], "prompt_number": 101 }, { "cell_type": "code", "collapsed": true, "input": [ "# There are handy ways to make arrays full of ones and zeros\n", "print np.zeros(5)\n", "print np.zeros([5, 5])\n", "print np.ones(3)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 0. 0. 0. 0. 0.]\n", "[[ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]\n", " [ 0. 0. 0. 0. 0.]]\n", "[ 1. 1. 1.]\n" ] } ], "prompt_number": 107 }, { "cell_type": "code", "collapsed": false, "input": [ "E = np.empty(5)\n", "print E\n", "E.fill(2)\n", "print E\n", "\n", "# arr = malloc(5 * sizeof(double))\n", "# memset(arr, 5, 5 * sizeof(double))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 1.71777771e-316 1.27945216e-316 6.75386947e-317 5.20185118e-317\n", " 6.90396305e-310]\n", "[ 2. 2. 2. 2. 2.]\n" ] } ], "prompt_number": 111 }, { "cell_type": "code", "collapsed": true, "input": [ "# You can also easily make arrays of number sequences\n", "np.identity(5)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 112, "text": [ "array([[ 1., 0., 0., 0., 0.],\n", " [ 0., 1., 0., 0., 0.],\n", " [ 0., 0., 1., 0., 0.],\n", " [ 0., 0., 0., 1., 0.],\n", " [ 0., 0., 0., 0., 1.]])" ] } ], "prompt_number": 112 }, { "cell_type": "code", "collapsed": false, "input": [ "# Some other useful routines for creating new arrays\n", "# Read the help page for these functions using np.arange? etc.\n", "print np.arange(0, 10)\n", "print np.linspace(0, 10, 5)\n", "print np.linspace(0, 10, 100)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[0 1 2 3 4 5 6 7 8 9]\n", "[ 0. 2.5 5. 7.5 10. ]\n", "[ 0. 0.1010101 0.2020202 0.3030303 0.4040404\n", " 0.50505051 0.60606061 0.70707071 0.80808081 0.90909091\n", " 1.01010101 1.11111111 1.21212121 1.31313131 1.41414141\n", " 1.51515152 1.61616162 1.71717172 1.81818182 1.91919192\n", " 2.02020202 2.12121212 2.22222222 2.32323232 2.42424242\n", " 2.52525253 2.62626263 2.72727273 2.82828283 2.92929293\n", " 3.03030303 3.13131313 3.23232323 3.33333333 3.43434343\n", " 3.53535354 3.63636364 3.73737374 3.83838384 3.93939394\n", " 4.04040404 4.14141414 4.24242424 4.34343434 4.44444444\n", " 4.54545455 4.64646465 4.74747475 4.84848485 4.94949495\n", " 5.05050505 5.15151515 5.25252525 5.35353535 5.45454545\n", " 5.55555556 5.65656566 5.75757576 5.85858586 5.95959596\n", " 6.06060606 6.16161616 6.26262626 6.36363636 6.46464646\n", " 6.56565657 6.66666667 6.76767677 6.86868687 6.96969697\n", " 7.07070707 7.17171717 7.27272727 7.37373737 7.47474747\n", " 7.57575758 7.67676768 7.77777778 7.87878788 7.97979798\n", " 8.08080808 8.18181818 8.28282828 8.38383838 8.48484848\n", " 8.58585859 8.68686869 8.78787879 8.88888889 8.98989899\n", " 9.09090909 9.19191919 9.29292929 9.39393939 9.49494949\n", " 9.5959596 9.6969697 9.7979798 9.8989899 10. ]\n" ] } ], "prompt_number": 115 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "EXERCISE 3 - Storing data in arrays" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Copy your code from Exercise 2 into the box below, and do the following:\n", "\n", "1. Modify your code to store the calculation results in an array instead of a list. HINT: \n", "Make sure to pre-allocate space for the array using `np.zeros()` or something similar. Pre-allocate an\n", "array of length 100, as if we were going to fill in 100 time steps, including n0.\n", "2. Imagine that each discrete time step actually represents 0.25 of an hour. Create an array `t` storing\n", "the time, in hours, of each step of the calculations (for example, t0 is 0, t1 is 0.25, t2 is 0.5, etc.)\n", "up to 100 time steps (the final time will thus be 24.75).\n", "3. Use boolean indexing to extract the value of `n` corresponding to a `t` of 0.5." ] }, { "cell_type": "code", "collapsed": true, "input": [ "r = 0.6\n", "K = 100.0\n", "n = np.zeros(100)\n", "n[0] = 10\n", "\n", "n[1] = round(n[0] + r*n[0] * (1 - n[0] / K))\n", "n[2] = round(n[1] + r*n[1] * (1 - n[1] / K))\n", "n[3] = round(n[2] + r*n[2] * (1 - n[2] / K))\n", "\n", "#print n\n", "\n", "t = np.arange(0, 25, 0.25)\n", "#print t\n", "\n", "print n[t > 0.5]" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 34. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0. 0. 0. 0. 0. 0.]\n" ] } ], "prompt_number": 120 }, { "cell_type": "markdown", "metadata": {}, "source": [ "[^Back to top](#Table-of-Contents)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "4. Repeating yourself" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So far, everything that we've done could, in principle, be done by hand calculation. In this section\n", "and the next, we really start to take advantage of the power of programming languages to do things\n", "for us automatically.\n", "\n", "We start here with ways to repeat yourself. The two most common ways of doing this are known as for\n", "loops and while loops. For loops in Python are useful when you want to cycle over all of the items\n", "in a collection (such as all of the elements of an array), and while loops are useful when you want to\n", "cycle for an indefinite amount of time until some condition is met.\n", "\n", "The basic examples below will work for looping over lists, tuples, and arrays. Looping over dictionaries\n", "is a bit different, since there is a key and a value for each item in a dictionary. Have a look at the\n", "Python docs for more information." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# A basic for loop - don't forget the white space!\n", "wordlist = ['hi', 'hello', 'bye']\n", "for word in wordlist:\n", " print word + '!'\n", " print '------'\n", "\n", "print 'Done loop'" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "hi!\n", "------\n", "hello!\n", "------\n", "bye!\n", "------\n", "Done loop\n" ] } ], "prompt_number": 124 }, { "cell_type": "code", "collapsed": false, "input": [ "# Whitespace is an important delimiter for code blocks in Python\n", "from __future__ import braces" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "SyntaxError", "evalue": "not a chance (, line 1)", "output_type": "pyerr", "traceback": [ "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m from __future__ import braces\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m not a chance\n" ] } ], "prompt_number": 128 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Note on indentation**: Notice the indentation once we enter the for loop. Every idented statement after the for loop declaration is part of the for loop. This rule holds true for while loops, if statements, functions, etc. Required identation is one of the reasons Python is such a beautiful language to read.\n", "\n", "If you do not have consistent indentation you will get an `IndentationError`. Fortunately, most code editors will ensure your indentation is correction." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Indentation error: Fix it!\n", "for word in wordlist:\n", " print word\n", " print word" ], "language": "python", "metadata": {}, "outputs": [ { "ename": "IndentationError", "evalue": "unindent does not match any outer indentation level (, line 4)", "output_type": "pyerr", "traceback": [ "\u001b[1;36m File \u001b[1;32m\"\"\u001b[1;36m, line \u001b[1;32m4\u001b[0m\n\u001b[1;33m print word\u001b[0m\n\u001b[1;37m ^\u001b[0m\n\u001b[1;31mIndentationError\u001b[0m\u001b[1;31m:\u001b[0m unindent does not match any outer indentation level\n" ] } ], "prompt_number": 129 }, { "cell_type": "code", "collapsed": true, "input": [ "# Sum all of the values in a collection using a for loop" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": true, "input": [ "# Often we want to loop over the indexes of a collection, not just the items" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": true, "input": [ "# While loops are useful when you don't know how many steps you will need,\n", "# and want to stop once a certain condition is met." ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__TIP:__ Once we start really generating useful and large collections of data, it becomes unwieldy to\n", "inspect our results manually. The code below shows how to make a very simple plot of an array.\n", "We'll do more plotting later on, this is just to get started." ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Load up pylab, a useful plotting library\n", "%matplotlib inline\n", "from matplotlib import pyplot as plt\n", "\n", "# Make some x and y data and plot it\n", "x = np.linspace(0, 2 * np.pi)\n", "y = np.sin(x)\n", "plt.plot(x, y)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 5, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\ngg==\n", "text": [ "" ] } ], "prompt_number": 5 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "EXERCISE 4 - Using loops to repeat calculations" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "FINALLY, let's get smart about our calculations of `nt`. Copy your code from Exercise 3 into the box\n", "below, and do the following:\n", "\n", "1. Write a for loop to fill in the values of `nt` for 100 time steps. HINT: You will need to \n", "create an array of the step numbers using a command like `step = range(1, 100)`. (Why does\n", "this list start at 1 and not at 0?). Then, loop over the values of the step list,\n", "and use each step value to index the array `n`.\n", "1. Plot the array `n`.\n", "1. Play around with the values of `r` and `K` and see how it changes the plot. What happens if you set\n", "`r` to 1.9 or 3?\n", "\n", "__Bonus__\n", "\n", "1. Modify your code to use a while loop that will stop your calculation once the population size is\n", "greater than 90. HINT: Start a step counter `i` at 1, and check that the value in `n[i-1]` is less than 90\n", "each time around the loop. Increment the step counter within the loop so that you have a record\n", "of what step the calculation stopped at." ] }, { "cell_type": "code", "collapsed": true, "input": [ "r = 0.6\n", "K = 100.0\n", "n = np.zeros(100, dtype=float)\n", "n[0] = 10\n", "\n", "steps = range(1, 100)\n", "for idx in steps:\n", " n[idx] = round(n[idx - 1] + r*n[idx - 1] * (1 - n[idx - 1]/K))\n", " \n", "plt.plot(n)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 135, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\nGwyGSqfTqc3Pz99tsViKb/VZtHAAAEJPVNjff//9XyUnJ3tvfM1utxtZluWIiFiW5Ww2m+lWn0XY\nAwCEgd/vF7XV19drcnJyjgb+nJSU5A183d3drbjxz4GNiPzYsGHDhm3wm9isDmzxNAQUCoVfoVD4\nb3492Hs7AACAOJKdjcMwDO/xeNRERG63O0WlUrVINTYAAARHsrA3Go12juNYIiKO41iTyWSTamwA\nAAiOqFscFxYWfrB3794F58+fH8cwDP/aa6/96yOPPPKJ2Wy2NjQ0TNRoNC6r1WpOSkryDUHNAAAw\nWME2/Qe6ff755w9lZmaenDx58imLxfJyqPYrh62hoSFdr9f/XafTHc/Ozj5WXl7+G7/fT62trcpF\nixZVTpkyxWkwGCq8Xm9SuGsN1dbZ2Rk3c+bM2iVLlnway3Ph9XqTVqxY8besrKwTU6dOrTtw4MC8\nWJ2L0tLS9Tqd7nhOTs7RwsLCv167du3OWJmL1atXb1OpVPyNJ73c7mcvLS1dP3ny5FOZmZknv/ji\ni4KB7CMkP0hnZ2dcRkbG9/X19Zr29vaEGTNmHK6rq5sa7gkO1eZ2u9W1tbUz/X4/Xbp0abRWq/2u\nrq5u6osvvvjHDRs2vOT3+8lisbz88ssvW8Jda6i2jRs3/o9Vq1b9ZenSpXa/30+xOhdPPPEEt3Xr\n1jV+v586OjrifT5fYizORX19vWbSpEk/XLt27U6/309ms/nD9957j42Vufjyyy/vr6mpyb0x7Pv6\n2Y8fP66bMWPG4fb29oT6+npNRkbG911dXcP620dIfpB9+/bNX7x48a7An8vKyorLysqKwz3B4doe\neeQRW2Vl5aLMzMyTHo+H8ft7fiFkZmaeDHdtodgaGxvT8vPzq/bs2fNgYGUfi3Ph8/kSJ02a9MPN\nr8fiXLS2tiq1Wu13giAkd3R0xC9ZsuTTiooKQyzNxc2ns/f1s5eWlq6/sTuyePHiXfv377+nv/FD\ncm+cpqam1PT09MbAn9PS0s42NTWlhmLfcuNyuTS1tbW58+bNO8jzPMMwDE/UczYTz/NMuOsLheef\nf37T66+//uKwYcO6A6/F4lzU19dPGj9+/LnVq1e/O2vWrJqnnnrq7StXroyKxblQKpXCCy+8sHHi\nxIkNEyZMaE5KSvIZDIbKWJyLgL5+9ubm5glpaWlnA+8baJ6GJOxvdc59LLp8+fLoFStWfFReXv7c\nmDFjLt34vb6uTYg2n3322RKVStWSm5tb6+/juotYmYvOzs74mpqaWc8888xbNTU1s0aNGnXl5tuM\nxMpcnD59OmPz5s3rXC6Xprm5ecLly5dHv//++/9y43tiZS5upb+ffSDzEpKwT01NbWpsbEwP/Lmx\nsTH9xt9MsaCjoyNhxYoVHxUVFW0PnJYai9cm7Nu371673W6cNGlSfWFh4Qd79uxZWFRUtD0W5yIt\nLe1sWlra2Tlz5nxNRLRy5cq/1dTUzFKr1Z5Ym4tDhw7l3XvvvfvGjh3bGh8f37l8+fKP9+/fPz8W\n5yKgr78TN+fp2bNn01JTU5v6Gy8kYZ+Xl3fo1KlTU1wul6a9vf2ODz/88FGj0WgPxb7lwO/3K9au\nXbtVp9PVrVu3bnPg9Vi8NqG0tPSVxsbG9Pr6+kk7dux4bOHChXu2b99eFItzoVarPenp6Y1Op1NL\nRFRVVbUoOzv7+NKlSz+NtbnIyso6eeDAgXuuXr06wu/3K6qqqhbpdLq6WJyLgL7+ThiNRvuOHTse\na29vv6O+vn7SqVOnpsydO7e63wFDdfBh586d/6zVar/LyMj4vrS0dH24D4aEcvvqq6/uUygU3TNm\nzDg8c+bM2pkzZ9Z+/vnnD7W2tirz8/Orov20sr42h8OxIHA2TqzOxeHDh2fk5eV9PX369CPLli37\n2OfzJcbqXGzYsOGlwKmXTzzxBNfe3p4QK3Px2GOPfZCSktKckJDQnpaW1rht27bVt/vZ//CHP7yS\nkZHxfWZm5sldu3YtHsg+RF1UBQAAkSUsjyUEAIDQQtgDAMQAhD0AQAxA2AMAxACEPQBADEDYAwDE\ngP8PK4OP7HRLT40AAAAASUVORK5CYII=\n", "text": [ "" ] } ], "prompt_number": 135 }, { "cell_type": "markdown", "metadata": {}, "source": [ "[^Back to top](#Table-of-Contents)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "5. Making choices" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Often we want to check if a condition is True and take one action if it is, and another action if the\n", "condition is False. We can achieve this in Python with an if statement.\n", "\n", "__TIP:__ You can use any expression that returns a boolean value (`True` or `False`) in an if statement.\n", "Common boolean operators are `==`, `!=`, `<`, `<=`, `>`, `>=`. You can also use `is` and `is not` if you want to\n", "check if two variables are identical in the sense that they are stored in the same location in memory." ] }, { "cell_type": "code", "collapsed": false, "input": [ "print bool(1)\n", "print bool(0)\n", "\n", "z = 1\n", "if z:\n", " print 'z is non-zero'" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "True\n", "False\n", "z is non-zero\n" ] } ], "prompt_number": 139 }, { "cell_type": "code", "collapsed": false, "input": [ "print bool('hello')\n", "print bool('')\n", "print bool('1')\n", "print bool('0')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "True\n", "False\n", "True\n", "True\n" ] } ], "prompt_number": 143 }, { "cell_type": "code", "collapsed": true, "input": [ "# A simple if statement\n", "x = 3\n", "if x > 0:\n", " print 'x is positive'\n", "elif x < 0:\n", " print 'x is negative'\n", "else:\n", " print 'x is zero'" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "x is positive\n" ] } ], "prompt_number": 144 }, { "cell_type": "code", "collapsed": true, "input": [ "# If statements can rely on boolean variables" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "EXERCISE 5 - Making the model stochastic with an if statement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Deterministic models are boring, so let's introduce some element of randomness into our logistic\n", "growth model. We'll model a simple \"catastrophe\" process, in which a catastrophe happens in 10% of the\n", "time steps that reduces the population back down to the size at n0. Copy your code from Exercise 4\n", "into the box below, and do the following:\n", "\n", "1. Inside your for loop, add a variable called `cata`, for catastrophe, that will be True if a catastrophe\n", "has occurred, and False if it hasn't. A simple way to do this is to generate a random number using\n", "`np.random.rand()`, which will give you a pseudorandom number between 0 and 1. Check whether this number\n", "is less than 0.1 - this check will be True 10% of the time.\n", "1. Using your boolean variable `cata`, add an if statement to your for loop that checks whether `cat` is\n", "true in each time step. If it is true, set the population back to the size at n[0]. Otherwise, perform\n", "the usual logistic growth calculation.\n", "1. Plot your results. Run the cell again to see a different random population growth path.\n", "\n", "__Bonus__\n", "\n", "1. Now that you have the array `n`, count the number of time steps in which the population was above 50.\n", "Although you can do this with a for loop (loop through each value of `nt`, check if it is > 50, and if so\n", "increment a counter), you can do this in one line with a simple boolean operation.\n", "HINT: If you take the sum of a boolean array (using `np.sum()`), it will give you the number of\n", "`True` values (since a `True` is considered to be a 1, and `False` is a 0)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "a = 'x is nonzero' if x else 'x is zero'\n", "print a" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "x is nonzero\n" ] } ], "prompt_number": 149 }, { "cell_type": "code", "collapsed": true, "input": [ "r = 0.6\n", "K = 100.0\n", "n = np.zeros(100, dtype=float)\n", "n[0] = 10\n", "\n", "steps = range(1, 100)\n", "for idx in steps:\n", " catastrophe = np.random.rand() < 0.42\n", " if catastrophe:\n", " n[idx] = n[0]\n", " else:\n", " n[idx] = round(n[idx - 1] + r*n[idx - 1] * (1 - n[idx - 1]/K))\n", " \n", "plt.plot(n)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 151, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n8atXr667++6735zI+cBxHLW3tydv2bLl9aVLl55ZtmzZ6Y8//njDRMyPPXv2PJmTk3NqxYoVJ7dt\n2/aHvr6+yRMlH3bs2PFienq6Xzj5ROm379mz58nFixd/sWTJkrN//vOfC7Xcw3Sjh4aG4hctWnTe\n6/VmDQwMJK5aterE6dOnl0U6M8P1aW5uzqirq1vNcRx1dXVNz87OPnf69OllP/zhD3/29NNP/4jj\nOHK5XE888cQTrkjbGo7Pz3/+83964IEHfr958+YKjuNoouYDx3H00EMPufft2/cwx3E0ODiY0NHR\nkTTR8sPr9WYtXLjwQl9f32SO46ikpOS13/3ud86Jkg9/+ctfbq+trc0Virrcbz916lTOqlWrTgwM\nDCR6vd6sRYsWnR8eHo5Tu4fpRh89evSWu+66613+/0899VTpU089VRrpzIzU55577imvrKzctGTJ\nkrM+n8/OcUz4lyxZcjbStoX609jYmFlQUFB1+PDhO3hPfSLmA8dx1NHRkbRw4cIL4uMTLT/a2tpS\ns7OzzwUCgZTBwcGEu++++81Dhw45JlI+iKeJy/32PXv2PCmMdNx1113vfvTRR19TS9/0vV+uXLky\nb/78+V+9kyYzM/PylStXVNaQxSYNDQ1ZdXV1uRs2bPjE7/fb7Xa7n4jNIPL7/fZI2xdqHn/88Wef\neeaZH8bFxX21qHoi5gMRkdfrXZiWltayY8eOl9asWVP76KOP/ub69evTJlp+pKamBv75n//55wsW\nLLg0d+7cpuTk5A6Hw1E50fJBiNxvb2pqmpuZmXmZP0+rlpou6nLz1ica3d3d07ds2fLG3r17fzBj\nxowu4XdK8/tjhbfeeuvu9PT0q7m5uXWczJqFiZAPPENDQwm1tbVrvve97/1nbW3tmmnTpl0Xb7Ex\nEfLjyy+/XPTcc8/tbGhoyGpqaprb3d09/cCBAw8Kz5kI+SCH2m/Xki+mi/q8efOuNDY2frWBbWNj\n43xhazMRGBwcTNyyZcsb27dv389P+Zxo8/uPHj16a0VFRdHChQu927Zte+Xw4cN3bt++ff9Eywee\nzMzMy5mZmZfXrVtXQ0S0devW12tra9dkZGT4JlJ+HDt2LO/WW289OmvWrLaEhISh++67748fffTR\nLRMtH4TI1Qmxll6+fDlz3rx5qi+jNF3U8/Lyjn3xxRc3NTQ0ZA0MDEx67bXXvl1UVFRh9n2sCsdx\ntkceeWRfTk7O6Z07dz7HH59o8/v37Nnz48bGxvler3fhq6++ev+dd955eP/+/dsnWj7wZGRk+ObP\nn99YX1+fTURUVVW1afny5ac2b9785kTKj6VLl579+OOPv9bb2zuF4zhbVVXVppycnNMTLR+EyNWJ\noqKiildfffX+gYGBSV6vd+EXX3xx0/r169V3bQrFQMA777zzt9nZ2ecWLVp0fs+ePU9GemAinJ8P\nPvjgNpvNNrJq1aoTq1evrlu9enXdwYMHv9HW1pZaUFBQFetTtqQ+Ho9nIz/7ZSLnw4kTJ1bl5eXV\n3HzzzZ/ee++9f+zo6EiaiPnx9NNP/4if0vjQQw+5BwYGEidKPtx///2vzJkzpykxMXEgMzOz8cUX\nX9yh9Nt/+tOf/njRokXnlyxZcvbdd9+9S8s9FBcfAQAAiC4i9o5SAAAA5gNRBwCAGAKiDgAAMQRE\nHQAAYgiIOgAAxBAQdQAAiCH+HxY1zkURdvN9AAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 151 }, { "cell_type": "code", "collapsed": false, "input": [ "if x: print 'x is nonzero'" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "x is nonzero\n" ] } ], "prompt_number": 148 }, { "cell_type": "markdown", "metadata": {}, "source": [ "[^Back to top](#Table-of-Contents)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "6. Creating chunks with functions and modules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "One way to write a program is to simply string together commands, like the ones described above, in a long\n", "file, and then to run that file to generate your results. This may work, but it can be cognitively difficult\n", "to follow the logic of programs written in this style. Also, it does not allow you to reuse your code\n", "easily - for example, what if we wanted to run our logistic growth model for several different choices of\n", "initial parameters?\n", "\n", "The most important ways to \"chunk\" code into more manageable pieces is to create functions and then\n", "to gather these functions into modules, and eventually packages. Below we will discuss how to create\n", "functions and modules. A third common type of \"chunk\" in Python is classes, but we will not be covering\n", "object-oriented programming in this workshop." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# We've been using functions all day" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": true, "input": [ "# It's very easy to write your own functions\n", "def multiply(x, y):\n", " return x * y" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 152 }, { "cell_type": "code", "collapsed": true, "input": [ "# Once a function is \"run\" and saved in memory, it's available just like any other function\n", "print type(multiply)\n", "print multiply(2, 3)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\n", "6\n" ] } ], "prompt_number": 154 }, { "cell_type": "code", "collapsed": true, "input": [ "# It's useful to include docstrings to dxescribe what your function does\n", "def say_hello(time, people):\n", " \"\"\"\n", " This function says a greeting. useful for engendering good will.\n", " \n", " Parameters\n", " ==========\n", " time : str\n", " The time at which we are greeting our guest.\n", " people : object\n", " The people who we want to greet (could be a string, a list, etc.)\n", " \"\"\"\n", " \n", " return 'Good ' + time + ', ' + people" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 157 }, { "cell_type": "code", "collapsed": false, "input": [ "say_hello?" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 156 }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Docstrings**: A docstring is a special type of comment that tells you what a function does. You can see them when you ask for help about a function." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# All arguments must be present, or the function will return an error" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "code", "collapsed": true, "input": [ "# Keyword arguments can be used to make some arguments optional by giving them a default value\n", "# All mandatory arguments must come first, in order" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "EXERCISE 6 - Creating a logistic growth function" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Finally, let's turn our logistic growth model into a function that we can use over and over again. \n", "Copy your code from Exercise 5 into the box below, and do the following:\n", "\n", "1. Turn your code into a function called `logistic_growth` that takes four arguments: `r`, `K`, `n0`,\n", "and `p` (the probability of a catastrophe). Make `p` a keyword argument with a default value of 0.1.\n", "Have your function return the `n` array.\n", "1. Write a nice docstring describing what your function does.\n", "1. In a subsequent cell, call your function with different values of the parameters to make sure it works.\n", "Store the returned value of `n` and make a plot from it.\n", "\n", "__Bonus__\n", "\n", "1. Refactor your function by pulling out the line that actually performs the calculation of the new\n", "population given the old population. Make this line another function called `grow_one_step` that takes\n", "in the old population, `r`, and `K`, and returns the new population. Have your `logistic_growth` function\n", "use the `grow_one_step` function to calculate the new population in each time step." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# Set up initial model parameters\n", "def logistic_growth(r, K, n0, prob_catastrophe=0.1):\n", " \"\"\"\n", " Function to simulate discrete time stocastic logistic growth. \n", " \n", " Parameters\n", " ----------\n", " r : float\n", " Reproductive rate of the population.\n", " K : int\n", " Carrying capacity of the environment.\n", " n0 : int\n", " Initial population size\n", " prob_catastrophe : float\n", " Probability of a catastrophe resetting the population\n", " size to n0 (default: 0.1)\n", " \n", " Returns\n", " -------\n", " n : ndarray\n", " Array of 100 time steps of population values\n", " \"\"\"\n", " \n", " n = np.zeros(100)\n", " n[0] = float(n0)\n", "\n", " # Loop through all time steps\n", " steps = np.arange(1, 100)\n", " for idx in steps:\n", " cata = np.random.rand() < prob_catastrophe\n", " if cata:\n", " n[idx] = n[0]\n", " else:\n", " n[idx] = grow_one_step(n[idx -1], r, K)\n", " return n\n", "\n", "\n", "def grow_one_step(prev_population, r, K):\n", " return round(prev_population + r*prev_population*(1 - prev_population/K))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "grow_one_step" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 8, "text": [ "" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "n = logistic_growth(0.6, 100, 10)\n", "plt.plot(n)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 9, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n+P955LMQKTxA9wAAAABJRU5ErkJggg==\n", "text": [ "" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Advanced solution--we can change `logistic_growth` to a function that takes a *function* `step_func` as one of its arguments. That is, when you call `logistic_growth` you pass in as an argument a *function* that itself takes three arguments: the previous population size, the growth rate, and the carrying capacity. It then returns the population size for the next time step. Note that `logistic_growth` no longer has the \"stochastic\" feature...yet. We'll come to that:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "# Set up initial model parameters\n", "def grow_one_step(prev_population, r, K):\n", " return round(prev_population + r*prev_population*(1 - prev_population/K))\n", "\n", "\n", "def logistic_growth(r, K, n0, step_func=grow_one_step):\n", " \"\"\"\n", " Function to simulate discrete time stocastic logistic growth. \n", " \n", " Parameters\n", " ----------\n", " r : float\n", " Reproductive rate of the population.\n", " K : int\n", " Carrying capacity of the environment.\n", " n0 : int\n", " Initial population size\n", " step_func : function\n", " A function which, given the previous population, the growth rate,\n", " and the carrying capacity, returns the population size at the next\n", " time step. By default this computes:\n", " \n", " .. math::\n", " \n", " n(t+1) = n(t) + r n(t) [1 - n(t) / K]\n", " \n", " Returns\n", " -------\n", " n : ndarray\n", " Array of 100 time steps of population values\n", " \"\"\"\n", " \n", " n = np.zeros(100)\n", " n[0] = float(n0)\n", "\n", " # Loop through all time steps\n", " steps = np.arange(1, 100)\n", " for idx in steps:\n", " n[idx] = step_func(n[idx -1], r, K)\n", " \n", " return n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "plt.plot(logistic_growth(0.6, 100, 10))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 16, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\nGwyGSqfTqc3Pz99tsViKb/VZtHAAAEJPVNjff//9XyUnJ3tvfM1utxtZluWIiFiW5Ww2m+lWn0XY\nAwCEgd/vF7XV19drcnJyjgb+nJSU5A183d3drbjxz4GNiPzYsGHDhm3wm9isDmzxNAQUCoVfoVD4\nb3492Hs7AACAOJKdjcMwDO/xeNRERG63O0WlUrVINTYAAARHsrA3Go12juNYIiKO41iTyWSTamwA\nAAiOqFscFxYWfrB3794F58+fH8cwDP/aa6/96yOPPPKJ2Wy2NjQ0TNRoNC6r1WpOSkryDUHNAAAw\nWME2/Qe6ff755w9lZmaenDx58imLxfJyqPYrh62hoSFdr9f/XafTHc/Ozj5WXl7+G7/fT62trcpF\nixZVTpkyxWkwGCq8Xm9SuGsN1dbZ2Rk3c+bM2iVLlnway3Ph9XqTVqxY8besrKwTU6dOrTtw4MC8\nWJ2L0tLS9Tqd7nhOTs7RwsLCv167du3OWJmL1atXb1OpVPyNJ73c7mcvLS1dP3ny5FOZmZknv/ji\ni4KB7CMkP0hnZ2dcRkbG9/X19Zr29vaEGTNmHK6rq5sa7gkO1eZ2u9W1tbUz/X4/Xbp0abRWq/2u\nrq5u6osvvvjHDRs2vOT3+8lisbz88ssvW8Jda6i2jRs3/o9Vq1b9ZenSpXa/30+xOhdPPPEEt3Xr\n1jV+v586OjrifT5fYizORX19vWbSpEk/XLt27U6/309ms/nD9957j42Vufjyyy/vr6mpyb0x7Pv6\n2Y8fP66bMWPG4fb29oT6+npNRkbG911dXcP620dIfpB9+/bNX7x48a7An8vKyorLysqKwz3B4doe\neeQRW2Vl5aLMzMyTHo+H8ft7fiFkZmaeDHdtodgaGxvT8vPzq/bs2fNgYGUfi3Ph8/kSJ02a9MPN\nr8fiXLS2tiq1Wu13giAkd3R0xC9ZsuTTiooKQyzNxc2ns/f1s5eWlq6/sTuyePHiXfv377+nv/FD\ncm+cpqam1PT09MbAn9PS0s42NTWlhmLfcuNyuTS1tbW58+bNO8jzPMMwDE/UczYTz/NMuOsLheef\nf37T66+//uKwYcO6A6/F4lzU19dPGj9+/LnVq1e/O2vWrJqnnnrq7StXroyKxblQKpXCCy+8sHHi\nxIkNEyZMaE5KSvIZDIbKWJyLgL5+9ubm5glpaWlnA+8baJ6GJOxvdc59LLp8+fLoFStWfFReXv7c\nmDFjLt34vb6uTYg2n3322RKVStWSm5tb6+/juotYmYvOzs74mpqaWc8888xbNTU1s0aNGnXl5tuM\nxMpcnD59OmPz5s3rXC6Xprm5ecLly5dHv//++/9y43tiZS5upb+ffSDzEpKwT01NbWpsbEwP/Lmx\nsTH9xt9MsaCjoyNhxYoVHxUVFW0PnJYai9cm7Nu371673W6cNGlSfWFh4Qd79uxZWFRUtD0W5yIt\nLe1sWlra2Tlz5nxNRLRy5cq/1dTUzFKr1Z5Ym4tDhw7l3XvvvfvGjh3bGh8f37l8+fKP9+/fPz8W\n5yKgr78TN+fp2bNn01JTU5v6Gy8kYZ+Xl3fo1KlTU1wul6a9vf2ODz/88FGj0WgPxb7lwO/3K9au\nXbtVp9PVrVu3bnPg9Vi8NqG0tPSVxsbG9Pr6+kk7dux4bOHChXu2b99eFItzoVarPenp6Y1Op1NL\nRFRVVbUoOzv7+NKlSz+NtbnIyso6eeDAgXuuXr06wu/3K6qqqhbpdLq6WJyLgL7+ThiNRvuOHTse\na29vv6O+vn7SqVOnpsydO7e63wFDdfBh586d/6zVar/LyMj4vrS0dH24D4aEcvvqq6/uUygU3TNm\nzDg8c+bM2pkzZ9Z+/vnnD7W2tirz8/Orov20sr42h8OxIHA2TqzOxeHDh2fk5eV9PX369CPLli37\n2OfzJcbqXGzYsOGlwKmXTzzxBNfe3p4QK3Px2GOPfZCSktKckJDQnpaW1rht27bVt/vZ//CHP7yS\nkZHxfWZm5sldu3YtHsg+RF1UBQAAkSUsjyUEAIDQQtgDAMQAhD0AQAxA2AMAxACEPQBADEDYAwDE\ngP8PK4OP7HRLT40AAAAASUVORK5CYII=\n", "text": [ "" ] } ], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This now implements our basic `logistic_growth` (without the stochastic feature). The default `step_func` computes the next time step normally, and we can call `logistic_growth` without specifying the `step_func` argument, since it has a default value pointing to the `grow_one_step` function.\n", "\n", "However, our `logistic_growth` function was designed so that the `step_func` called in its internal loop can be customized, so we can implement more sophisticated growth models without rewriting the entire `logistic_growth` function. This is a \"Pythonic\" example of a programming design pattern called the [strategy pattern](http://en.wikipedia.org/wiki/Strategy_pattern). So now say we want to implement the stochastic model. We can define a new function that wraps the basic `grow_one_step` but includes the probability for a catastrophe:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def grow_one_step_stochastic(prev_population, rate, carrying_capacity, init_population=10,\n", " prob_catastrophe=0.1):\n", " \"\"\"\n", " Computes the next population size using a stochastic model.\n", " \n", " With a probability of `prob_catastrophe` (given as a value from 0 to 1), the population\n", " size is reset back to `init_population` rather than growing larger.\n", " \"\"\"\n", " \n", " cata = np.random.rand() < prob_catastrophe\n", " if cata:\n", " return init_population\n", " else:\n", " return grow_one_step(prev_population, rate, carrying_capacity)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "But now we have a problem--the interface defined by `logistic_growth` requires the function passed to `step_func` to take three arguments. But our `grow_one_step_stochastic` requires five! We have specified *defaults* for `init_population` and `prob_catastrophe`. So if we pass in `grow_one_step_stochastic` with the defaults for this arguments it will still work:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "n = logistic_growth(0.6, 100, 10, step_func=grow_one_step_stochastic)\n", "plt.plot(n)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 18, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\nSUVORK5CYII=\n", "text": [ "" ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "But what if we want to change to `init_population` and `prob_catastrophe` parameters to `grow_one_step_stocastic`? One thing we can do is use an advanced technique called \"partial evaluation\". We create a new function from `grow_one_step_stochastic` that has new values for `init_population` and `prob_catastrophe` \"baked in\", while leaving the other arguments (rate, etc.) as required arguments.\n", "\n", "Python has a utility in the `functools` library called `functools.partial` that makes it easy to make partially-evaluated functions. To start with a simpler example:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import functools\n", "\n", "def say_hello(name, time='morning'):\n", " print 'Good', time, name + '!'\n", " \n", "say_hello('Erik', time='afternoon')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Good afternoon Erik!\n" ] } ], "prompt_number": 21 }, { "cell_type": "markdown", "metadata": {}, "source": [ "If I want to say \"Good afternoon\" I have to specify the `time='afternoon'` argument every time I call `say_hello` (otherwise it will say \"Good morning\" by default). I can \"bake in\" `time='afternoon'` by making a partial evaluation of `say_hello`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "say_good_afternoon = functools.partial(say_hello, time='afternoon')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "say_good_afternoon('Erik')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Good afternoon Erik!\n" ] } ], "prompt_number": 24 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use this with our `grow_one_step_stochastic` to specify, for example, the probability of catastrophe when we pass it in to `logistic_growth`:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "n = logistic_growth(0.6, 100, 10,\n", " step_func=functools.partial(grow_one_step_stochastic, prob_catastrophe=0.4))\n", "plt.plot(n)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 27, "text": [ "[]" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n6mVlZdXBYNAPABAMBv3l5eVV9IuFIAiCGMHDKRzIsH379pfffffd27q6uhZ6vd7Q73//+/921113\n/Z+KioqDV65cWZaTk3P54MGDFWlpaQp73hAEQRDbMBOQl3u9+eab31m5cuW5FStWXAgEAr+xIg9W\nX1euXFlaXFx8JD8//3RBQcGpvXv3/pzjOOju7k7fvHlzzQ033NDo8/kO9fT0pDldVjte4+Pj8evX\nr2+48847X4vleuA4Dnp6etK2bdv26qpVq86uXr36zCeffLIpFutjz549j+fn559es2bNye3bt/+v\n4eHh62KlHnbu3PlCRkZGSLj4ROm779mz5/EVK1ZcWLly5bm33367VEse1As9Pj4ev3z58otNTU05\no6OjiYWFhcfOnDmz2unKtOvV3t6e2dDQsJ7jOOjv75+bl5d3/syZM6t/9atf/fuTTz75a47jIBAI\n/OY3v/lNwOmy2vF6+umnf/HDH/7wr1u3bq3mOA5itR44joMHHngguG/fvgc5joOxsbGESCSSGmv1\n0dTUlJObm/vl8PDwdRzHQUVFxSt/+ctf/LFSD++999636+vri4RGXe67nz59Or+wsPDY6OhoYlNT\nU87y5csvTkxMxKnlQb3QH3300T9s2bLlLf7vJ554ovKJJ56odLoynXrdddddVTU1NZtXrlx5rqOj\nw8txxPCvXLnynNNls/rV3NycXVJSUnv48OHbeU89FuuB4ziIRCKpubm5X4rfj7X66O7uTs/Lyzsf\nDofnj42NJdx5552vHTp0yBdL9SBeJi733ffs2fO4MNKxZcuWtz7++ONvqqVP/eyX1tbWJUuXLv16\nb2V2dnZLa2vrEtr5RAOXL1/OaWhoKNq0adOnoVDI6/V6QwBkBVEoFNKxyT86eeyxx5556qmnfhUX\nF/f11plYrAcAgKamptxFixZ17ty588UNGzbUP/zww38eHBycE2v1kZ6eHv7lL3/59LJly64sXry4\nLS0tLeLz+WpirR6EyH33tra2xdnZ2S3857TaUupGXW7deqwxMDAwd9u2bX/bu3fvIykpKdMeB6G0\nvt8tvP7663dmZGRcLSoqauBk9izEQj3wjI+PJ9TX12/42c9+9t/r6+s3zJkzZ1B8xEYs1MelS5eW\nP/vss49evnw5p62tbfHAwMDcl1566UfCz8RCPcih9t211At1o75kyZLW5ubmrx9R0NzcvFTY28QC\nY2Njidu2bfvbjh079vNLPmNtff9HH310S3V1dVlubm7T9u3bXz58+PAdO3bs2B9r9cCTnZ3dkp2d\n3XLTTTd9BgBwzz33vFpfX78hMzOzI5bq4/PPP994yy23fLRgwYLuhISE8e9///v/+fHHH/9DrNWD\nELk2IbalLS0t2UuWLGlVS4+6Ud+4cePnFy5cuOHy5cs5o6Ojs1555ZV7y8rKqmnnwyocx3keeuih\nffn5+WceffTRZ/n3Y219/549e37b3Ny8tKmpKffAgQP33XHHHYf379+/I9bqgSczM7Nj6dKlzY2N\njXkAALW1tZsLCgpOb9269bVYqo9Vq1ad++STT745NDSUxHGcp7a2dnN+fv6ZWKsHIXJtoqysrPrA\ngQP3jY6Ozmpqasq9cOHCDTfffPNR1QStmAh44403/ikvL+/88uXLL+7Zs+dxpycm7Hy9//77t3o8\nnsnCwsJj69evb1i/fn3Dm2+++Z3u7u70kpKSWrcv2ZJ61dXV3cavfonlejh27Fjhxo0bP1u3bt3x\nu++++z8jkUhqLNbHk08++Wt+SeMDDzwQHB0dTYyVerjvvvtezsrKaktMTBzNzs5ufuGFF3Yqffd/\n+7d/++3y5csvrly58txbb721RUseipuPEARBkOjC0icfIQiCIPaCRh1BEMRFoFFHEARxEWjUEQRB\nXAQadQRBEBeBRh1BEMRF/D9+pTaagvxeeAAAAABJRU5ErkJggg==\n", "text": [ "" ] } ], "prompt_number": 27 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "EXERCISE 7 - Putting the growth functions in a module" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can make our functions more easily reusable by placing them into modules that we can import, just\n", "like we have been doing with `numpy`. It's pretty simple to do this.\n", "\n", "1. Copy your function(s) from Exercise 6 into a new text file, in the same directory as this notebook,\n", "called `pop.py`.\n", "1. In the cell below, type `import pop` to import the module. Type `pop.` and hit tab to see the available\n", "functions in the module. Try running the logistic growth function that was imported from the module with\n", "a few different parameter values." ] }, { "cell_type": "code", "collapsed": true, "input": [ "# import pop\n", "# plt.plot(pop.logistic_growth(0.6, 100, 10))" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[^Back to top](#Table-of-Contents)" ] } ], "metadata": {} } ] }