<jupyter_start><jupyter_text>Python LibrariesWe 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.<jupyter_code>#IPython is what you are using now to run the notebook
import jupyter
#print ("Jupyter version:      %6.6s (need at least 1.0)" % jupyter.__version__)

# Numpy is a library for working with Arrays
import numpy as np
print ("Numpy version:        %6.6s (need at least 1.7.1)" % np.__version__)

# SciPy implements many different numerical algorithms
import scipy as sp
print ("SciPy version:        %6.6s (need at least 0.12.0)" % sp.__version__)

# Pandas makes working with data tables easier
import pandas as pd
print ("Pandas version:       %6.6s (need at least 0.11.0)" % pd.__version__)

# Module for plotting
import matplotlib
print ("Mapltolib version:    %6.6s (need at least 1.2.1)" % matplotlib.__version__)

# SciKit Learn implements several Machine Learning algorithms
import sklearn
print ("Scikit-Learn version: %6.6s (need at least 0.13.1)" % sklearn.__version__)

# Requests is a library for getting data from the Web
import requests
print ("requests version:     %6.6s (need at least 1.2.3)" % requests.__version__)

# Networkx is a library for working with networks
import networkx as nx
print ("NetworkX version:     %6.6s (need at least 1.7)" % nx.__version__)

#BeautifulSoup is a library to parse HTML and XML documents
import beautifulSoup
print ("BeautifulSoup version:%6.6s (need at least 3.2)" % BeautifulSoup.__version__)

#MrJob is a library to run map reduce jobs on Amazon's computers
import mrjob
print ("Mr Job version:       %6.6s (need at least 0.4)" % mrjob.__version__)

#Pattern has lots of tools for working with data from the internet
import pattern
print ("Pattern version:      %6.6s (need at least 2.6)" % pattern.__version__)<jupyter_output>Numpy version:        1.12.1 (need at least 1.7.1)
SciPy version:        0.19.0 (need at least 0.12.0)
Pandas version:       0.20.1 (need at least 0.11.0)
Mapltolib version:     2.0.2 (need at least 1.2.1)
Scikit-Learn version: 0.18.1 (need at least 0.13.1)
requests version:     2.14.2 (need at least 1.2.3)
NetworkX version:       1.11 (need at least 1.7)<jupyter_text>If any of these libraries are missing or out of date, you will need to [install them](https://github.com/cs109/content/wiki/Installing-Pythoninstalling-additional-libraries) and restart IPython  Hello matplotlib The notebook integrates nicely with Matplotlib, the primary plotting package for python. This should embed a figure of a sine wave:<jupyter_code>#this line prepares IPython for working with matplotlib
%matplotlib inline  

# this actually imports matplotlib
import matplotlib.pyplot as plt  

x = np.linspace(0, 10, 30)  #array of 30 points from 0 to 10
y = np.sin(x)
z = y + np.random.normal(size=30) * .2
plt.plot(x, y, 'ro-', label='A sine wave')
plt.plot(x, z, 'b-', label='Noisy sine')
plt.legend(loc = 'lower right')
plt.xlabel("X axis")
plt.ylabel("Y axis")<jupyter_output><empty_output><jupyter_text>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)  Hello NumpyThe 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)<jupyter_code>print ("Make a 3 row x 4 column array of random numbers")
x = np.random.random((3, 4))
print (x)
print

print ("Add 1 to every element")
x = x + 1
print (x)
print

print ("Get the element at row 1, column 2")
print (x[1, 2])
print

# The colon syntax is called "slicing" the array. 
print ("Get the first row")
print (x[0, :])
print

print ("Get every 2nd column of the first row")
print (x[0, ::2])
print<jupyter_output>Make a 3 row x 4 column array of random numbers
[[ 0.80596117  0.58085638  0.2137176   0.55817447]
 [ 0.71444621  0.56043767  0.33289552  0.11722417]
 [ 0.71265339  0.78697654  0.81669209  0.65359971]]
Add 1 to every element
[[ 1.80596117  1.58085638  1.2137176   1.55817447]
 [ 1.71444621  1.56043767  1.33289552  1.11722417]
 [ 1.71265339  1.78697654  1.81669209  1.65359971]]
Get the element at row 1, column 2
1.33289552396
Get the first row
[ 1.80596117  1.58085638  1.2137176   1.55817447]
Get every 2nd column of the first row
[ 1.80596117  1.2137176 ]<jupyter_text>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<jupyter_code>#your code here<jupyter_output><empty_output><jupyter_text>Call the `x.max` function again, but use the `axis` keyword to print the maximum of each row in x.<jupyter_code>#your code here<jupyter_output><empty_output><jupyter_text>Here's a way to quickly simulate 500 coin "fair" coin tosses (where the probabily of getting Heads is 50%, or 0.5)<jupyter_code>x = np.random.binomial(500, .5)
print "number of heads:", x<jupyter_output><empty_output><jupyter_text>Repeat this simulation 500 times, and use the [plt.hist() function](http://matplotlib.org/api/pyplot_api.htmlmatplotlib.pyplot.hist) to plot a histogram of the number of Heads (1s) in each simulation<jupyter_code>#your code here<jupyter_output><empty_output><jupyter_text>The Monty Hall ProblemHere's a fun and perhaps surprising statistical riddle, and a good way to get some practice writing python functionsIn 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.We can answer the problem by running simulations in Python. We'll do it in several parts.First, write a function called `simulate_prizedoor`. This function will simulate the location of the prize in many games -- see the detailed specification below:<jupyter_code>"""
Function
--------
simulate_prizedoor

Generate a random array of 0s, 1s, and 2s, representing
hiding a prize between door 0, door 1, and door 2

Parameters
----------
nsim : int
    The number of simulations to run

Returns
-------
sims : array
    Random array of 0s, 1s, and 2s

Example
-------
>>> print simulate_prizedoor(3)
array([0, 0, 2])
"""
def simulate_prizedoor(nsim):
    #compute here
    return answer
#your code here<jupyter_output><empty_output><jupyter_text>Next, write a function that simulates the contestant's guesses for `nsim` simulations. Call this function `simulate_guess`. The specs:<jupyter_code>"""
Function
--------
simulate_guess

Return any strategy for guessing which door a prize is behind. This
could be a random strategy, one that always guesses 2, whatever.

Parameters
----------
nsim : int
    The number of simulations to generate guesses for

Returns
-------
guesses : array
    An array of guesses. Each guess is a 0, 1, or 2

Example
-------
>>> print simulate_guess(5)
array([0, 0, 0, 0, 0])
"""
#your code here<jupyter_output><empty_output><jupyter_text>Next, write a function, `goat_door`, to simulate randomly revealing one of the goat doors that a contestant didn't pick.<jupyter_code>"""
Function
--------
goat_door

Simulate the opening of a "goat door" that doesn't contain the prize,
and is different from the contestants guess

Parameters
----------
prizedoors : array
    The door that the prize is behind in each simulation
guesses : array
    THe door that the contestant guessed in each simulation

Returns
-------
goats : array
    The goat door that is opened for each simulation. Each item is 0, 1, or 2, and is different
    from both prizedoors and guesses

Examples
--------
>>> print goat_door(np.array([0, 1, 2]), np.array([1, 1, 1]))
>>> array([2, 2, 0])
"""
#your code here<jupyter_output><empty_output><jupyter_text>Write a function, `switch_guess`, that represents the strategy of always switching a guess after the goat door is opened.<jupyter_code>"""
Function
--------
switch_guess

The strategy that always switches a guess after the goat door is opened

Parameters
----------
guesses : array
     Array of original guesses, for each simulation
goatdoors : array
     Array of revealed goat doors for each simulation

Returns
-------
The new door after switching. Should be different from both guesses and goatdoors

Examples
--------
>>> print switch_guess(np.array([0, 1, 2]), np.array([1, 2, 1]))
>>> array([2, 0, 0])
"""
#your code here<jupyter_output><empty_output><jupyter_text>Last function: write a `win_percentage` function that takes an array of `guesses` and `prizedoors`, and returns the percent of correct guesses<jupyter_code>"""
Function
--------
win_percentage

Calculate the percent of times that a simulation of guesses is correct

Parameters
-----------
guesses : array
    Guesses for each simulation
prizedoors : array
    Location of prize for each simulation

Returns
--------
percentage : number between 0 and 100
    The win percentage

Examples
---------
>>> print win_percentage(np.array([0, 1, 2]), np.array([0, 0, 0]))
33.333
"""
#your code here<jupyter_output><empty_output><jupyter_text>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?<jupyter_code>#your code here<jupyter_output><empty_output>