/
blinky.py
141 lines (105 loc) · 3.73 KB
/
blinky.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
"""
This file contains code used in "Think Stats",
by Allen B. Downey, available from greenteapress.com
Copyright 2010 Allen B. Downey
License: GNU GPLv3 http://www.gnu.org/licenses/gpl.html
This file contains a solution to the Blink Monty Problem, by
Allen Downey:
Suppose you are on Let's Make a Deal and you are playing the Monty
Hall Game, with one difference: before you went on the show you
analyzed tapes of previous shows and discovered that Monty has a tell:
when the contestant picks the correct door, Monty is more likely to
blink.
Specifically, of the 15 shows you watched, the contestant chose the
correct door 5 times, and Monty blinked three of those times. Of the
other 10 times, Monty blinked three times.
Assume that you choose Door A. Monty opens door B and blinks. What
should you do, and what is your chance of winning?
You can read a discussion of this problem at XXX
NAME: blinky.py
"""
import _04_Pmf
import _05_myplot
def _make_uniform_suite(low, high, steps, name=''):
"""
Makes a PMF that represents a suite of hypotheses with equal p.
Args:
low: low end of range
high: high end of range
steps: number of values
name: string name for the Pmf
Returns:
Pmf object
"""
hypos = [low + (high - low) * i / (steps - 1.0) for i in range(steps)]
pmf = _04_Pmf._make_pmf_from_list(hypos, name=name)
return pmf
def _update(suite, evidence):
"""
Updates a suite of hypotheses based on new evidence.
Modifies the suite directly; if you want to keep the original, make a copy.
Args:
suite: Pmf object
evidence: whatever kind of object Likelihood expects
"""
for hypo in suite._values():
likelihood = _likelihood(evidence, hypo)
suite._mult(hypo, likelihood)
suite._normalize()
def _likelihood(evidence, hypo):
"""
Computes the likelihood of the evidence assuming the hypothesis is true.
Args:
evidence: a tuple of (number of successes, number of failures)
hypo: float probability of success
Returns:
unnormalized likelihood of getting the given number of successes
and failures if the probability of success is p
"""
heads, tails = evidence
p = hypo
return pow(p, heads) * pow(1 - p, tails)
def _total_probability(pmf1, pmf2, func):
"""
Enumerates pairs from the Pmfs, calls the func, and returns
the total probability.
Args:
pmf1: Pmf object
pmf2: Pmf object
func: a callable that takes a value from each Pmf and returns probability.
"""
total = 0.0
for x, px in pmf1._items():
for y, py in pmf2._items():
if px and py:
total += px * py * func(x, y)
return total
def _prob_winning(pbA, pbC):
"""
Computes the probability that the car is behind door A:
Args:
pbA: probability that Monty blinks if the car is behind A
pbC: probability that Monty blinks if the car is behind C
"""
pea = 0.5 * pbA
pec = pbC
pae = pea / (pea + pec)
return pae
def main():
print('pae', 0.3 / (0.3 + 3.0 / 13))
doorA = _make_uniform_suite(0.0, 1.0, 101, name='Door A')
evidence = 3, 2
_update(doorA, evidence)
doorC = _make_uniform_suite(0.0, 1.0, 101, name='Door C')
evidence = 3, 10
_update(doorC, evidence)
print(_total_probability(doorA, doorC, _prob_winning))
# plot the posterior distributions
_05_myplot._pmfs([doorA, doorC])
_05_myplot._save(root='blinky',
formats=['pdf', 'png'],
title='Probability of blinking',
xlabel='P(blink)',
ylabel='Posterior probability')
if __name__ == '__main__':
main()