Skip to content

Commit 0a5baee

Browse files
author
Hugo Bowne-Anderson
authored
Add text to PyMC3 section NB2
1 parent fea5529 commit 0a5baee

1 file changed

Lines changed: 111 additions & 8 deletions

File tree

notebooks/2.Parameter_estimation_hypothesis_testing.ipynb

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -264,13 +264,54 @@
264264
"## 3. Bayesian parameter estimation using PyMC3"
265265
]
266266
},
267+
{
268+
"cell_type": "markdown",
269+
"metadata": {},
270+
"source": [
271+
"Well done! You've learnt the basics of Bayesian model building. The steps are\n",
272+
"1. To completely specify the model in terms of _probability distributions_. This includes specifying \n",
273+
" - what the form of the sampling distribution of the data is _and_ \n",
274+
" - what form describes our _uncertainty_ in the unknown parameters (This formulation is adapted from [Fonnesbeck's workshop](https://github.com/fonnesbeck/intro_stat_modeling_2017/blob/master/notebooks/2.%20Basic%20Bayesian%20Inference.ipynb) as Chris said it so well there).\n",
275+
"2. Calculate the _posterior distribution_.\n",
276+
"\n",
277+
"In the above, the form of the sampling distribution of the data was Binomial (described by the likelihood) and the uncertainty around the unknown parameter $p$ captured by the prior."
278+
]
279+
},
280+
{
281+
"cell_type": "markdown",
282+
"metadata": {},
283+
"source": [
284+
"Now it is time to do the same using the **probabilistic programming language** PyMC3. There's _loads_ about PyMC3 and this paradigm, two of which are\n",
285+
"- _probabililty distributions_ are first class citizens, in that we can assign them to variables and use them intuitively to mirror how we think about priors, likelihoods & posteriors.\n",
286+
"- PyMC3 calculates the posterior for us!\n",
287+
"\n",
288+
"Under the hood, PyMC3 will compute the posterior using a sampling based approach called Markov Chain Monte Carlo (MCMC) or Variational Inference. Check the [PyMC3 docs](https://docs.pymc.io/) for more on these. \n",
289+
"\n",
290+
"But now, it's time to bust out some MCMC and get sampling!"
291+
]
292+
},
267293
{
268294
"cell_type": "markdown",
269295
"metadata": {},
270296
"source": [
271297
"### Parameter estimation I: click-through rate"
272298
]
273299
},
300+
{
301+
"cell_type": "markdown",
302+
"metadata": {},
303+
"source": [
304+
"A common experiment in tech data science is to test a product change and see how it affects a metric that you're interested in. Say that I don't think enough people are clicking a button on my website & I hypothesize that it's because the button is a similar color to the background of the page. Then I can set up two pages and send some people to each: the first the original page, the second a page that is identical, except that it has a button that is of higher contrast and see if more people click through. This is commonly referred to as an A/B test and the metric of interest is click-through rate (CTR), what proportion of people click through. Before even looking at two rates, let's use PyMC3 to estimate one.\n",
305+
"\n"
306+
]
307+
},
308+
{
309+
"cell_type": "markdown",
310+
"metadata": {},
311+
"source": [
312+
"First generate click-through data, given a CTR $p_a=0.15$."
313+
]
314+
},
274315
{
275316
"cell_type": "code",
276317
"execution_count": null,
@@ -283,6 +324,17 @@
283324
"n_successes_a = np.sum(np.random.binomial(N,p_a))"
284325
]
285326
},
327+
{
328+
"cell_type": "markdown",
329+
"metadata": {},
330+
"source": [
331+
"Now it's time to build your probability model. Noticing that our model of having a constant CTR resulting in click or not is a biased coin flip,\n",
332+
"- the sampling distribution is binomial and we need to encode this in the likelihood;\n",
333+
"- there is a single parameter $p$ that we need to describe the uncertainty around, using a prior and we'll use a uniform prior for this.\n",
334+
"\n",
335+
"These are the ingredients for the model so let's now build it:"
336+
]
337+
},
286338
{
287339
"cell_type": "code",
288340
"execution_count": null,
@@ -294,14 +346,43 @@
294346
" # Prior on p\n",
295347
" prob = pm.Uniform('p')\n",
296348
" # Binomial Likelihood\n",
297-
" y = pm.Binomial('y', n=N, p=prob, observed=n_successes_a)\n",
298-
"\n",
349+
" y = pm.Binomial('y', n=N, p=prob, observed=n_successes_a)"
350+
]
351+
},
352+
{
353+
"cell_type": "markdown",
354+
"metadata": {},
355+
"source": [
356+
"**Discussion:** \n",
357+
"- What do you think of the API for PyMC3. Does it reflect how we think about model building?"
358+
]
359+
},
360+
{
361+
"cell_type": "markdown",
362+
"metadata": {},
363+
"source": [
364+
"It's now time to sample from the posterior using PyMC3. You'll also plot the posterior:"
365+
]
366+
},
367+
{
368+
"cell_type": "code",
369+
"execution_count": null,
370+
"metadata": {},
371+
"outputs": [],
372+
"source": [
299373
"with Model:\n",
300-
" samples = pm.sample(1000, njobs=1)\n",
374+
" samples = pm.sample(2000, njobs=1)\n",
301375
"\n",
302376
"pm.plot_posterior(samples);"
303377
]
304378
},
379+
{
380+
"cell_type": "markdown",
381+
"metadata": {},
382+
"source": [
383+
"**For discussion:** Interpret the posterior ditribution. What would your tell the non-technical manager of your growth team about the CTR?"
384+
]
385+
},
305386
{
306387
"cell_type": "markdown",
307388
"metadata": {},
@@ -313,7 +394,7 @@
313394
"cell_type": "markdown",
314395
"metadata": {},
315396
"source": [
316-
"In this exercise, you'll calculate the posterior mean beak depth of Galapagos finches."
397+
"In this exercise, you'll calculate the posterior mean beak depth of Galapagos finches in a given species. First you'll load the data and subset wrt species:"
317398
]
318399
},
319400
{
@@ -328,16 +409,38 @@
328409
"df_scandens = df_12.loc[df_12['species'] == 'scandens']"
329410
]
330411
},
412+
{
413+
"cell_type": "markdown",
414+
"metadata": {},
415+
"source": [
416+
"To specify the full probabilty model, you need\n",
417+
"- a likelihood function for the data &\n",
418+
"- priors for all unknowns.\n",
419+
"\n",
420+
"What is the likelihood here? Let's plot the measurements below and see that they look approximately Gaussian/normal so you'll use a normal likelihood $y_i\\sim \\mathcal{N}(\\mu, \\sigma^2)$. The unknowns here are the mean $\\mu$ and standard deviation $\\sigma$ and we'll use weakly informative priors on both\n",
421+
"- a normal prior for $\\mu$ with mean $10$ and standard deviation $5$;\n",
422+
"- a uniform prior for $\\sigma$ bounded between $0$ and $10$.\n",
423+
"\n",
424+
"We can discuss biological reasons for these priors also but you can also test that the posteriors are relativelyt robust to the choice of prior here due to the amount of data."
425+
]
426+
},
427+
{
428+
"cell_type": "code",
429+
"execution_count": null,
430+
"metadata": {},
431+
"outputs": [],
432+
"source": [
433+
"sns.distplot(df_fortis['blength']);"
434+
]
435+
},
331436
{
332437
"cell_type": "code",
333438
"execution_count": null,
334439
"metadata": {},
335440
"outputs": [],
336441
"source": [
337442
"with pm.Model() as model:\n",
338-
" \"\"\"\n",
339-
" The priors for each group.\n",
340-
" \"\"\"\n",
443+
" # Prior for mean & standard deviation\n",
341444
" μ_1 = pm.Normal('μ_1', mu=10, sd=5)\n",
342445
" σ_1 = pm.Lognormal('σ_1', 0, 10)\n",
343446
" # Gaussian Likelihood\n",
@@ -415,7 +518,7 @@
415518
"outputs": [],
416519
"source": [
417520
"with Model:\n",
418-
" samples = pm.sample(1000, njobs=1)\n",
521+
" samples = pm.sample(2000, njobs=1)\n",
419522
"pm.plot_posterior(samples);"
420523
]
421524
},

0 commit comments

Comments
 (0)