Think Bayes solutions: Chapter 2

This notebook presents solutions to exercises in Think Bayes.

Copyright 2016 Allen B. Downey

MIT License: https://opensource.org/licenses/MIT


In [1]:
from __future__ import print_function, division

from thinkbayes2 import Hist, Pmf

% matplotlib inline

Exercise 2.1 In Section 2.3 I said that the solution to the cookie problem generalizes to the case where we draw multiple cookies with replacement.

But in the more likely scenario where we eat the cookies we draw, the likelihood of each draw depends on the previous draws.

Modify the solution in this chapter to handle selection without replacement. Hint: add instance variables to Cookie to represent the hypothetical state of the bowls, and modify Likelihood accordingly. You might want to define a Bowl object.

Solution Here's the original solution from the book:


In [2]:
pmf = Pmf()
pmf.Set('Bowl 1', 0.5)
pmf.Set('Bowl 2', 0.5)

pmf.Mult('Bowl 1', 0.75)
pmf.Mult('Bowl 2', 0.5)

pmf.Normalize()

pmf.Print()


Bowl 1 0.6000000000000001
Bowl 2 0.4

We could write it more concisely like this:


In [3]:
pmf = Pmf(['Bowl 1', 'Bowl 2'])

pmf['Bowl 1'] *= 0.75
pmf['Bowl 2'] *= 0.5

pmf.Normalize()
pmf.Print()


Bowl 1 0.6000000000000001
Bowl 2 0.4

And we can do a second update, with a chocolate cookie, like this:


In [4]:
pmf['Bowl 1'] *= 0.25
pmf['Bowl 2'] *= 0.5

pmf.Normalize()
pmf.Print()


Bowl 1 0.4285714285714286
Bowl 2 0.5714285714285714

Now let's solve the version of the problem where we don't replace the cookies.

We'll need an object to keep track of the number of cookies in each bowl. I'll use a Hist object, defined in thinkbayes2:


In [5]:
bowl1 = Hist(dict(vanilla=30, chocolate=10))
bowl2 = Hist(dict(vanilla=20, chocolate=20))

bowl1.Print()


chocolate 10
vanilla 30

Now I'll make a Pmf that contains the two bowls, giving them equal probability.


In [6]:
pmf = Pmf([bowl1, bowl2])
pmf.Print()


Hist({'vanilla': 30, 'chocolate': 10}) 0.5
Hist({'vanilla': 20, 'chocolate': 20}) 0.5

Here's a likelihood function that takes hypo, which is one of the Hist objects that represents a bowl, and data, which is either 'vanilla' or 'chocolate'.

likelihood computes the likelihood of the data under the hypothesis, and as a side effect, it removes one of the cookies from hypo


In [7]:
def likelihood(hypo, data):
    like = hypo[data] / hypo.Total()
    if like:
        hypo[data] -= 1
    return like

Now for the update. We have to loop through the hypotheses and compute the likelihood of the data under each hypothesis.


In [8]:
def update(pmf, data):
    for hypo in pmf:
        pmf[hypo] *= likelihood(hypo, data)
    return pmf.Normalize()

Here's the first update. The posterior probabilities are the same as what we got before, but notice that the number of cookies in each Hist has been updated.


In [9]:
update(pmf, 'vanilla')
pmf.Print()


Hist({'vanilla': 29, 'chocolate': 10}) 0.6
Hist({'vanilla': 19, 'chocolate': 20}) 0.4

So when we update again with a chocolate cookies, we get different likelihoods, and different posteriors.


In [10]:
update(pmf, 'chocolate')
pmf.Print()


Hist({'vanilla': 29, 'chocolate': 9}) 0.428571428571
Hist({'vanilla': 19, 'chocolate': 19}) 0.571428571429

If we get 10 more chocolate cookies, that eliminates Bowl 1 completely


In [11]:
for i in range(10):
    update(pmf, 'chocolate')
    print(pmf[bowl1])


0.26213592233
0.136363636364
0.0610465116279
0.0238005289006
0.00806142034549
0.0023166023166
0.000535554894377
8.92990028278e-05
8.11875025371e-06
0.0

In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]:


In [ ]: