{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Homework 0\n", "\n", "### Due Tuesday, September 10 (but no submission is required)\n", "\n", "---\n", "\n", "Welcome to CS109 / STAT121 / AC209 / E-109 (http://cs109.org/). In this class, we will be using a variety of tools that will require some initial configuration. To ensure everything goes smoothly moving forward, we will setup the majority of those tools in this homework. While some of this will likely be dull, doing it now will enable us to do more exciting work in the weeks that follow without getting bogged down in further software configuration. This homework will not be graded, however it is essential that you complete it timely since it will enable us to set up your accounts. You do not have to hand anything in, with the exception of filling out the online survey. \n", "\n", "## Class Survey, Piazza, and Introduction\n", "\n", "**Class Survey**\n", "\n", "Please complete the mandatory course survey located [here](https://docs.google.com/spreadsheet/viewform?formkey=dFg1ZFJwLWJ6ZWhWR1JJb0tES3lGMEE6MA#gid=0). It should only take a few moments of your time. Once you fill in the survey we will sign you up to the course forum on Piazza and the dropbox system that you will use to hand in the homework. It is imperative that you fill out the survey on time as we use the provided information to sign you up for these services. \n", "\n", "**Piazza**\n", "\n", "Go to [Piazza](https://piazza.com/harvard/fall2013/cs109/home) and sign up for the class using your Harvard e-mail address. \n", "\n", "You will use Piazza as a forum for discussion, to find team members, to arrange appointments, and to ask questions. Piazza should be your primary form of communication with the staff. Use the staff e-mail (staff@cs109.org) only for individual requests, e.g., to excuse yourself from a mandatory guest lecture. All readings, homeworks, and project descriptions will be announced on Piazza first. \n", "\n", "**Introduction**\n", "\n", "Once you are signed up to the Piazza course forum, introduce yourself to your classmates and course staff with a follow-up post in the introduction thread. Include your name/nickname, your affiliation, why you are taking this course, and tell us something interesting about yourself (e.g., an industry job, an unusual hobby, past travels, or a cool project you did, etc.). Also tell us whether you have experience with data science. \n", "\n", "## Programming expectations\n", "\n", "All the assignments and labs for this class will use Python and, for the most part, the browser-based IPython notebook format you are currently viewing. Knowledge of Python is not a prerequisite for this course, **provided you are comfortable learning on your own as needed**. While we have strived to make the programming component of this course straightforward, we will not devote much time to teaching prorgramming or Python syntax. Basically, you should feel comfortable with:\n", "\n", "* How to look up Python syntax on Google and StackOverflow.\n", "* Basic programming concepts like functions, loops, arrays, dictionaries, strings, and if statements.\n", "* How to learn new libraries by reading documentation.\n", "* Asking questions on StackOverflow or Piazza.\n", "\n", "There are many online tutorials to introduce you to scientific python programming. [Here is one](https://github.com/jrjohansson/scientific-python-lectures) that is very nice. Lectures 1-4 are most relevant to this class.\n", "\n", "## Getting Python\n", "\n", "You will be using Python throughout the course, including many popular 3rd party Python libraries for scientific computing. [Anaconda](http://continuum.io/downloads) is an easy-to-install bundle of Python and most of these libraries. We recommend that you use Anaconda for this course.\n", "\n", "Please visit [this page](https://github.com/cs109/content/wiki/Installing-Python) and follow the instructions to set up Python\n", "\n", "\n", "\n", "## Hello, Python\n", "\n", "The IPython notebook is an application to build interactive computational notebooks. You'll be using them to complete labs and homework. Once you've set up Python, please download this page, and open it with IPython by typing\n", "\n", "```\n", "ipython notebook \n", "```\n", "\n", "For the rest of the assignment, use your local copy of this page, running on IPython.\n", "\n", "Notebooks are composed of many \"cells\", which can contain text (like this one), or code (like the one below). Double click on the cell below, and evaluate it by clicking the \"play\" button above, for by hitting shift + enter" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x = [10, 20, 30, 40, 50]\n", "for item in x:\n", " print \"Item is \", item" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Item is 10\n", "Item is 20\n", "Item is 30\n", "Item is 40\n", "Item is 50\n" ] } ], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Python Libraries\n", "\n", "We will be using a several different libraries throughout this course. If you've successfully completed the [installation instructions](https://github.com/cs109/content/wiki/Installing-Python), all of the following statements should run." ] }, { "cell_type": "code", "collapsed": false, "input": [ "#IPython is what you are using now to run the notebook\n", "import IPython\n", "print \"IPython version: %6.6s (need at least 1.0)\" % IPython.__version__\n", "\n", "# Numpy is a library for working with Arrays\n", "import numpy as np\n", "print \"Numpy version: %6.6s (need at least 1.7.1)\" % np.__version__\n", "\n", "# SciPy implements many different numerical algorithms\n", "import scipy as sp\n", "print \"SciPy version: %6.6s (need at least 0.12.0)\" % sp.__version__\n", "\n", "# Pandas makes working with data tables easier\n", "import pandas as pd\n", "print \"Pandas version: %6.6s (need at least 0.11.0)\" % pd.__version__\n", "\n", "# Module for plotting\n", "import matplotlib\n", "print \"Mapltolib version: %6.6s (need at least 1.2.1)\" % matplotlib.__version__\n", "\n", "# SciKit Learn implements several Machine Learning algorithms\n", "import sklearn\n", "print \"Scikit-Learn version: %6.6s (need at least 0.13.1)\" % sklearn.__version__\n", "\n", "# Requests is a library for getting data from the Web\n", "import requests\n", "print \"requests version: %6.6s (need at least 1.2.3)\" % requests.__version__\n", "\n", "# Networkx is a library for working with networks\n", "import networkx as nx\n", "print \"NetworkX version: %6.6s (need at least 1.7)\" % nx.__version__\n", "\n", "#BeautifulSoup is a library to parse HTML and XML documents\n", "import bs4\n", "print \"BeautifulSoup version:%6.6s (need at least 4.0)\" % bs4.__version__\n", "\n", "#MrJob is a library to run map reduce jobs on Amazon's computers\n", "import mrjob\n", "print \"Mr Job version: %6.6s (need at least 0.4)\" % mrjob.__version__\n", "\n", "#Pattern has lots of tools for working with data from the internet\n", "import pattern\n", "print \"Pattern version: %6.6s (need at least 2.6)\" % pattern.__version__" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "IPython version: 1.1.0 (need at least 1.0)\n", "Numpy version: 1.7.1 (need at least 1.7.1)\n", "SciPy version: 0.12.0 (need at least 0.12.0)\n", "Pandas version: 0.12.0 (need at least 0.11.0)\n", "Mapltolib version: 1.3.0 (need at least 1.2.1)\n", "Scikit-Learn version: 0.14.1 (need at least 0.13.1)\n", "requests version: 2.0.0 (need at least 1.2.3)\n", "NetworkX version: 1.8.1 (need at least 1.7)\n", "BeautifulSoup version: 4.3.2 (need at least 4.0)\n", "Mr Job version: 0.4.1 (need at least 0.4)\n", "Pattern version: 2.6 (need at least 2.6)\n" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "If any of these libraries are missing or out of date, you will need to [install them](https://github.com/cs109/content/wiki/Installing-Python#installing-additional-libraries) and restart IPython" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hello matplotlib" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The notebook integrates nicely with Matplotlib, the primary plotting package for python. This should embed a figure of a sine wave:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#this line prepares IPython for working with matplotlib\n", "%matplotlib inline \n", "\n", "# this actually imports matplotlib\n", "import matplotlib.pyplot as plt \n", "\n", "x = np.linspace(0, 10, 30) #array of 30 points from 0 to 10\n", "y = np.sin(x)\n", "z = y + np.random.normal(size=30) * .2\n", "plt.plot(x, y, 'ro-', label='A sine wave')\n", "plt.plot(x, z, 'b-', label='Noisy sine')\n", "plt.legend(loc = 'lower right')\n", "plt.xlabel(\"X axis\")\n", "plt.ylabel(\"Y axis\") " ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 8, "text": [ "" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": [ "If that last cell complained about the `%matplotlib` line, you need to update IPython to v1.0, and restart the notebook. See the [installation page](https://github.com/cs109/content/wiki/Installing-Python)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hello Numpy\n", "\n", "The Numpy array processing library is the basis of nearly all numerical computing in Python. Here's a 30 second crash course. For more details, consult Chapter 4 of Python for Data Analysis, or the [Numpy User's Guide](http://docs.scipy.org/doc/numpy-dev/user/index.html)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print \"Make a 3 row x 4 column array of random numbers\"\n", "x = np.random.random((3, 4))\n", "print x\n", "print\n", "\n", "print \"Add 1 to every element\"\n", "x = x + 1\n", "print x\n", "print\n", "\n", "print \"Get the element at row 1, column 2\"\n", "print x[1, 2]\n", "print\n", "\n", "# The colon syntax is called \"slicing\" the array. \n", "print \"Get the first row\"\n", "print x[0, :]\n", "print\n", "\n", "print \"Get every 2nd column of the first row\"\n", "print x[0, ::2]\n", "print" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Make a 3 row x 4 column array of random numbers\n", "[[ 0.30197511 0.16183333 0.55452118 0.16160336]\n", " [ 0.10382794 0.98268457 0.97507965 0.05796494]\n", " [ 0.23325497 0.92816451 0.30557064 0.57432936]]\n", "\n", "Add 1 to every element\n", "[[ 1.30197511 1.16183333 1.55452118 1.16160336]\n", " [ 1.10382794 1.98268457 1.97507965 1.05796494]\n", " [ 1.23325497 1.92816451 1.30557064 1.57432936]]\n", "\n", "Get the element at row 1, column 2\n", "1.97507965311\n", "\n", "Get the first row\n", "[ 1.30197511 1.16183333 1.55452118 1.16160336]\n", "\n", "Get every 2nd column of the first row\n", "[ 1.30197511 1.55452118]\n", "\n" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print the maximum, minimum, and mean of the array. This does **not** require writing a loop. In the code cell below, type `x.m`, to find built-in operations for common array statistics like this" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#your code here\n", "x.max(), x.min(), x.mean()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 11, "text": [ "(1.9826845720048296, 1.0579649404504141, 1.4450674640103411)" ] } ], "prompt_number": 11 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Call the `x.max` function again, but use the `axis` keyword to print the maximum of each row in x." ] }, { "cell_type": "code", "collapsed": false, "input": [ "#your code here\n", "x.max(axis=1)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 12, "text": [ "array([ 1.55452118, 1.98268457, 1.92816451])" ] } ], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's a way to quickly simulate 500 coin \"fair\" coin tosses (where the probabily of getting Heads is 50%, or 0.5)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "x = np.random.binomial(500, .5)\n", "print \"number of heads:\", x" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "number of heads: 234\n" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Repeat this simulation 500 times, and use the [plt.hist() function](http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.hist) to plot a histogram of the number of Heads (1s) in each simulation" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#your code here\n", "hist = np.array([])\n", "for i in range(500):\n", " x = np.random.binomial(500, .5)\n", " hist = np.append(hist, x)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "plt.hist(hist)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 21, "text": [ "(array([ 2., 23., 52., 73., 104., 96., 86., 41., 18., 5.]),\n", " array([ 220. , 226.1, 232.2, 238.3, 244.4, 250.5, 256.6, 262.7,\n", " 268.8, 274.9, 281. ]),\n", " )" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\nWj/+8Y+VSCQkVV/+lbJ/8MEH+Y/2fvOb39RLL70kqfqyS6sf+8nJSY2MjKi2tladnZ2KxWJm8vf1\n9Wn//v2SpH/+85/6yU9+IsnO8b9586ZGRkaUy+X0ne98R88++6wkO/kzmYz+8Ic/6Gtf+5peeukl\nPf/885LWmT8okaGhofztDz/8cNVtQRAE7733Xv72mTNnShVpXVbLuuj3v/99/ral/OfOnQtGRkaC\nv//97/lt1ZZ/pewXLlxY8bHVlj0IVs5/9+7dIJ1OP/ZYK/nn5+fz286dO5e/bSX/4ODgY9uCwE7+\n8+fP57ddvnw5f3s9+Us2xmltbX2ibdL6LrNQLqtl/eyzz/SrX/1KDQ0N+W1W8s/MzCgej2vLli3L\ntldb/pWyZ7NZnT59Wr/73e80Ojqa315t2aWV81+9elVbt27V6dOn9fHHH+e3W8m/uGYymcyyj1Rb\nyZ/NZpXL5ZTNZpd9099K/traWs3Pzyubzerq1ataWFiQtL78Jf/lJRcvXtShQ4cKbguq+DIL/541\nmUzq5z//ud577738P6Ws5P/oo4/0+uuva2JiYtljqjX/0uydnZ357efOncvfrtbs0vL8mUxGknTs\n2DF9+OGHamho0KZNm8zkXzQ+Pq7Dhw/n71vJ/+KLL6qvr0+S1Nvbm3+MlfwtLS06f/68FhYW9MIL\nL+hf//qXYrHYuvKXtOyHhoa0f/9+7dy5s+C29VxmoZxWyio9OsvZvn17/r6V/Ldv39b777+vTCaj\nZDKZn9lXY/7Vjr20fFFXY3Zp5fyLZ2x79uzRzMyMdu7caSq/JH311VfL/mVoJf/Y2JjeeOMN5XI5\nDQwM6Ic//KEkO/k3b96sH/zgB5IeXVF469atktaXv2Rlf/nyZe3evVvJZLLgNunRm4bSo79lF29X\n2kpZZ2Zm9Mwzz0hafkZgJf/im2rj4+PasWNHfnu15V8p++eff65vfOMbkh4VzqJqyy6tnP+FF17Q\n5OSkGhoadPfuXR04cECSnfySlMvltGnT8smvlfyLI45NmzYtO1mwkn/RvXv3dP/+/fx/z3ryl+Qb\ntJlMRm+//bYaGxslSXNzc3r11Vcf27b4z6lqu8zCSvl7e3v1wQcf6MGDB5Kkb3/72/n/GVbyS4/+\nwjp16pSSyaS+973vSaqu/Ktl/9Of/pT/JNTLL7+c/2RINWWXCh/7U6dOKRqNateuXWppaZFkK/9n\nn32mXC6XH19KdvJPTExofHxcknTgwAF961vfkmQn/7Vr1zQxMaEgCNTV1ZUv+/Xk53IJAOABvlQF\nAB6g7AHAA5Q9AHiAsgcAD1D2AOAByh4APEDZA4AHKHsA8MD/Amc8vAI5qz7JAAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 21 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## The Monty Hall Problem\n", "\n", "\n", "Here's a fun and perhaps surprising statistical riddle, and a good way to get some practice writing python functions\n", "\n", "In a gameshow, contestants try to guess which of 3 closed doors contain a cash prize (goats are behind the other two doors). Of course, the odds of choosing the correct door are 1 in 3. As a twist, the host of the show occasionally opens a door after a contestant makes his or her choice. This door is always one of the two the contestant did not pick, and is also always one of the goat doors (note that it is always possible to do this, since there are two goat doors). At this point, the contestant has the option of keeping his or her original choice, or swtiching to the other unopened door. The question is: is there any benefit to switching doors? The answer surprises many people who haven't heard the question before.\n", "\n", "We can answer the problem by running simulations in Python. We'll do it in several parts.\n", "\n", "First, write a function called `simulate_prizedoor`. This function will simulate the location of the prize in many games -- see the detailed specification below:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"\"\"\n", "Function\n", "--------\n", "simulate_prizedoor\n", "\n", "Generate a random array of 0s, 1s, and 2s, representing\n", "hiding a prize between door 0, door 1, and door 2\n", "\n", "Parameters\n", "----------\n", "nsim : int\n", " The number of simulations to run\n", "\n", "Returns\n", "-------\n", "sims : array\n", " Random array of 0s, 1s, and 2s\n", "\n", "Example\n", "-------\n", ">>> print simulate_prizedoor(3)\n", "array([0, 0, 2])\n", "\"\"\"\n", "def simulate_prizedoor(nsim):\n", " #compute here\n", " answer = np.floor(np.random.rand(nsim) * 3)\n", " return answer\n", "\n", "#your code here\n", "print simulate_prizedoor(10)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 2. 0. 1. 2. 2. 1. 1. 1. 0. 1.]\n" ] } ], "prompt_number": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, write a function that simulates the contestant's guesses for `nsim` simulations. Call this function `simulate_guess`. The specs:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"\"\"\n", "Function\n", "--------\n", "simulate_guess\n", "\n", "Return any strategy for guessing which door a prize is behind. This\n", "could be a random strategy, one that always guesses 2, whatever.\n", "\n", "Parameters\n", "----------\n", "nsim : int\n", " The number of simulations to generate guesses for\n", "\n", "Returns\n", "-------\n", "guesses : array\n", " An array of guesses. Each guess is a 0, 1, or 2\n", "\n", "Example\n", "-------\n", ">>> print simulate_guess(5)\n", "array([0, 0, 0, 0, 0])\n", "\"\"\"\n", "#your code here\n", "def simulate_guess(nsim):\n", " return np.ones(nsim) # Lucky number :)\n", "\n", "print simulate_guess(10)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n" ] } ], "prompt_number": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, write a function, `goat_door`, to simulate randomly revealing one of the goat doors that a contestant didn't pick." ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"\"\"\n", "Function\n", "--------\n", "goat_door\n", "\n", "Simulate the opening of a \"goat door\" that doesn't contain the prize,\n", "and is different from the contestants guess\n", "\n", "Parameters\n", "----------\n", "prizedoors : array\n", " The door that the prize is behind in each simulation\n", "guesses : array\n", " THe door that the contestant guessed in each simulation\n", "\n", "Returns\n", "-------\n", "goats : array\n", " The goat door that is opened for each simulation. Each item is 0, 1, or 2, and is different\n", " from both prizedoors and guesses\n", "\n", "Examples\n", "--------\n", ">>> print goat_door(np.array([0, 1, 2]), np.array([1, 1, 1]))\n", ">>> array([2, 2, 0])\n", "\"\"\"\n", "#your code here\n", "def goat_door(prizedoors, guesses):\n", " answer = np.ones(len(prizedoors)) * -1 # answer should not have -1\n", " answer[(prizedoors == guesses) & (prizedoors == 0)] = 1\n", " answer[(prizedoors == guesses) & (prizedoors == 1)] = 2\n", " answer[(prizedoors == guesses) & (prizedoors == 2)] = 0\n", " answer[(prizedoors != guesses) & (prizedoors == 0) & (guesses == 1)] = 2\n", " answer[(prizedoors != guesses) & (prizedoors == 0) & (guesses == 2)] = 1\n", " answer[(prizedoors != guesses) & (prizedoors == 1) & (guesses == 0)] = 2\n", " answer[(prizedoors != guesses) & (prizedoors == 1) & (guesses == 2)] = 0\n", " answer[(prizedoors != guesses) & (prizedoors == 2) & (guesses == 0)] = 1\n", " answer[(prizedoors != guesses) & (prizedoors == 2) & (guesses == 1)] = 0\n", " return answer\n", "\n", "print goat_door(np.array([0, 1, 2, 0, 0, 1, 1, 2, 2]), np.array([0, 1, 2, 1, 2, 0, 2, 0, 1]))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 1. 2. 0. 2. 1. 2. 0. 1. 0.]\n" ] } ], "prompt_number": 61 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Write a function, `switch_guess`, that represents the strategy of always switching a guess after the goat door is opened." ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"\"\"\n", "Function\n", "--------\n", "switch_guess\n", "\n", "The strategy that always switches a guess after the goat door is opened\n", "\n", "Parameters\n", "----------\n", "guesses : array\n", " Array of original guesses, for each simulation\n", "goatdoors : array\n", " Array of revealed goat doors for each simulation\n", "\n", "Returns\n", "-------\n", "The new door after switching. Should be different from both guesses and goatdoors\n", "\n", "Examples\n", "--------\n", ">>> print switch_guess(np.array([0, 1, 2]), np.array([1, 2, 1]))\n", ">>> array([2, 0, 0])\n", "\"\"\"\n", "#your code here\n", "def switch_guess(guesses, goatdoors):\n", " answer = np.ones(len(guesses)) * -1\n", " answer[(guesses == 0) & (goatdoors == 1)] = 2\n", " answer[(guesses == 0) & (goatdoors == 2)] = 1\n", " answer[(guesses == 1) & (goatdoors == 0)] = 2\n", " answer[(guesses == 1) & (goatdoors == 2)] = 0\n", " answer[(guesses == 2) & (goatdoors == 0)] = 1\n", " answer[(guesses == 2) & (goatdoors == 1)] = 0\n", " return answer\n", "\n", "print switch_guess(np.array([0, 0, 1, 1, 2, 2]), np.array([1, 2, 0, 2, 0, 1]))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[ 2. 1. 2. 0. 1. 0.]\n" ] } ], "prompt_number": 50 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Last function: write a `win_percentage` function that takes an array of `guesses` and `prizedoors`, and returns the percent of correct guesses" ] }, { "cell_type": "code", "collapsed": false, "input": [ "\"\"\"\n", "Function\n", "--------\n", "win_percentage\n", "\n", "Calculate the percent of times that a simulation of guesses is correct\n", "\n", "Parameters\n", "-----------\n", "guesses : array\n", " Guesses for each simulation\n", "prizedoors : array\n", " Location of prize for each simulation\n", "\n", "Returns\n", "--------\n", "percentage : number between 0 and 100\n", " The win percentage\n", "\n", "Examples\n", "---------\n", ">>> print win_percentage(np.array([0, 1, 2]), np.array([0, 0, 0]))\n", "33.333\n", "\"\"\"\n", "#your code here\n", "def win_percentage(guesses, pricedoors):\n", " return (guesses == pricedoors).mean()\n", "\n", "win_percentage(np.array([0, 1, 2]), np.array([0, 0, 0]))" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 55, "text": [ "0.33333333333333331" ] } ], "prompt_number": 55 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, put it together. Simulate 10000 games where contestant keeps his original guess, and 10000 games where the contestant switches his door after a goat door is revealed. Compute the percentage of time the contestant wins under either strategy. Is one strategy better than the other?" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#your code here\n", "prize_door = simulate_prizedoor(10000)\n", "original_guess = simulate_prizedoor(10000)\n", "\n", "# door showed to the contestant that is always a goat\n", "goat_doors = goat_door(prize_door, original_guess)\n", "\n", "# Case 1: stays with the same door\n", "print 'User wins %.2f%% if stays with the same door' % (win_percentage(original_guess, prize_door) * 100)\n", "\n", "# Case 2\n", "new_guess = switch_guess(original_guess, goat_doors)\n", "print 'User wins %.2f%% if stays changes the door after goat door is showed' % (win_percentage(new_guess, prize_door) * 100)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "User wins 33.33% if stays with the same door\n", "User wins 66.67% if stays changes the door after goat door is showed\n" ] } ], "prompt_number": 77 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Many people find this answer counter-intuitive (famously, PhD mathematicians have incorrectly claimed the result must be wrong. Clearly, none of them knew Python). \n", "\n", "One of the best ways to build intuition about why opening a Goat door affects the odds is to re-run the experiment with 100 doors and one prize. If the game show host opens 98 goat doors after you make your initial selection, would you want to keep your first pick or switch? Can you generalize your simulation code to handle the case of `n` doors?" ] } ], "metadata": {} } ] }