learn-bayesian-with-phoebe / Practitioner session 8 of 10
Learn Bayesian with Phoebe · Practitioner session 8 of 10

Checking the model

Sessions 5, 6 and 7 fitted models and read their posteriors. Tonight turns each model round and asks it to produce data. Before any voucher is counted, a prior predictive check simulates what the prior alone expects to see: the Wrong prior from session 2, Beta(40, 60), predicts roughly 40 percent redemption, and Halloway has never observed above 0.225 at any outlet, so it fails on that alone. After the fit, a posterior predictive check simulates fresh data from the posterior and lays it beside the data that were observed. Under complete pooling every outlet is predicted at the grand rate of 0.141, and Northgate's one redemption in eighteen looks like a surprise; under partial pooling, which shrinks Northgate toward 0.135 with data weight 18 / (18 + 116), it looks less like one. Then the part most write-ups leave out. Partial pooling passed every check in session 6 and still put Northgate at 0.124 against a true 0.192, because one in eighteen is what 0.192 looks like at that size. A check compares the model to the data you have, and the data you have were small.

🔴 Hardest Data scientists and analysts Anyone who has to sign off a fitted model 45 min
0-3 · Welcome 3-16 · Prior predictive, posterior predictive 16-40 · Build-along: the two checks in PyMC 6 and scipy 40-45 · Q&A
Part 0

Where session 8 sits

Session 4 taught the diagnostics: R-hat, ESS, divergences. A passing set proves the sampler explored this model's posterior, and nothing about whether the model is right. That second question is tonight's, and the tool for it is the same in both directions: make the model generate data and look. The source is McElreath's Statistical Rethinking, lecture 7, "Overfitting", which is where predictive checks are introduced. Whichever position you hold in leader session 5's argument about how a prior should be chosen, you can run the prior predictive check, which is why that session names it as the shared ground. Session 9 takes what survives tonight into the room where it is read aloud.

Live = presented in the 45 minutes Self-study = the full depth, after class 🔍 Every diagram zooms

★ What you walk out with tonight. Two checks you can run on any model from sessions 5 to 7. The prior predictive, pm.sample_prior_predictive(), which fails the Wrong prior at Westfield before a single voucher is counted. The posterior predictive, pm.sample_posterior_predictive(dt) and az.plot_ppc_dist(dt), which puts simulated months of 900 vouchers beside the observed 127. A scipy version of the same idea at Northgate that compares complete and partial pooling on the one count Halloway actually saw. And the sentence that keeps the checks honest: a model wrong in a way the data confirm passes them, and session 6's Northgate is the worked case.

LiveTwo directions, one move: make the model produce data4 min▶

Every model from sessions 5 to 7 is a machine for turning a rate into a count: a Beta on the rate, a Binomial on the redemptions. Run the machine forwards instead of backwards and it produces data. Run it forwards from the prior, before touching the observed counts, and you get the prior predictive: the redemption counts the prior alone considers plausible. Run it forwards from the posterior, after the fit, and you get the posterior predictive: the counts the fitted model expects in a fresh month. Both are simulations, both are cheap, and both end with the same question. Does this look like data that could exist, and does it look like the data that did?

The prior predictive is the check leader session 5 lands on as common ground, because it needs no agreement about where priors come from. A subjectivist, a reference-prior analyst and a weakly-informative one can all look at what Beta(40, 60) predicts for 900 vouchers and agree it is not a bakery chain. The posterior predictive is McElreath's lecture 7 tool for asking whether the fitted model has missed a shape in the data. Neither check produces a verdict on its own. They produce a picture, and the analyst produces the verdict.

Real world

The analyst who inherited the Wrong prior at Halloway did not argue about it. She ran sample_prior_predictive on the Westfield model, printed the counts it produced for 900 vouchers, and put the highest rate any outlet had ever recorded beside them: Hillcrest, 9 of 40, 0.225. The prior was predicting nearly twice that before it had seen a voucher. The meeting took four minutes.

Self-studyThe words that will keep coming back3 min▶
  • Prior predictive check. Simulate data from the prior alone, with no observed counts used, and ask whether it looks like data that could exist. pm.sample_prior_predictive() in PyMC 6; its deprecated samples argument is gone.
  • Posterior predictive check. Simulate new data from the posterior and compare to what was observed. pm.sample_posterior_predictive(dt), which gained sample_vars and freeze_vars in PyMC 6.
  • plot_ppc_dist. The ArviZ 1.x plot that lays the predictive draws over the observed data. It replaces the old plot_ppc and, like every ArviZ 1.x plot, returns a PlotCollection.
  • Grand rate. 0.141, the chain-wide redemption rate. What complete pooling predicts for every outlet.
  • Data weight. n / (n + 116) under partial pooling on the Halloway data: 0.13 at Northgate, 0.89 at Westfield. How far the posterior predictive for an outlet is allowed to leave the centre of 0.135.
  • What a check cannot catch. A model wrong in a way the data confirm. Northgate at 0.124 against 0.192, because 1 of 18 is what 0.192 looks like at that size.
  • Diagnostics. R-hat, ESS, divergences: proof the sampler explored this model's posterior. Not proof of the model.
  • LOO cross-validation. Named, not taught: the tool for comparing models by predictive accuracy on held-out points.
Part 1 · covers the prior predictive check and the prior it fails

Before the data: what does the prior alone predict?

7 min live

Session 2 put four priors on the bench: Flat Beta(1, 1), Weak Beta(2, 14), Informed Beta(12, 88), Wrong Beta(40, 60). Session 2 scored them after the fit. Tonight scores them before it, by asking each one what redemption rate it expects to see and laying that against the only fact about Halloway that needs no model: across twelve outlets the observed rate has ranged from 0.032 at Old Quay to 0.225 at Hillcrest. The figure draws each prior's predicted rate as a shape against that range.

Four priors, before any data: the redemption rate each one predicts, against what Halloway has ever seen. observed range across the twelve outlets: 0.032 (Old Quay) to 0.225 (Hillcrest) Flat · Beta(1, 1) mean 0.500 · 2 pseudo-obs rules nothing out extends to 1.0: every count from 0 to n equally plausible Weak · Beta(2, 14) mean 0.125 · 16 pseudo-obs inside the observed range Informed · Beta(12, 88) mean 0.120 · 100 pseudo-obs inside the observed range Wrong · Beta(40, 60) mean 0.400 · 100 pseudo-obs fails before any data are used centred at 0.400, nowhere Halloway has been 0 0.1 0.2 0.3 0.4 0.5 0.6 redemption rate the prior alone predicts Flat rules nothing out. Weak and Informed sit inside the range. Wrong predicts roughly 40 percent and fails before any data.
🔍 Click to zoom - three shapes touch the green band and one does not. The one that does not is worth 100 pseudo-observations, the same weight as the Informed prior beside it, which is the whole reason to look before fitting.
LiveThe Wrong prior fails on the highest number in the table3 min▶

Beta(40, 60) has mean 0.400 and is worth 100 pseudo-observations. Run the Westfield model forwards from it and the counts it produces for 900 vouchers sit around 40 percent redemption. Now the only fact you need: across the twelve outlets, in the month on the table, the highest observed rate anywhere is Hillcrest's 9 of 40, 0.225. The prior is predicting a business that Halloway has never once been, at any outlet, at any size. It has failed, and it failed with no data used, because the check never looked at Westfield's 127. It looked at what the prior expects and asked whether that could be a bakery chain.

This is what makes the prior predictive the shared ground of leader session 5's argument. The subjectivist says the prior encodes belief and nothing else; fine, but a belief that predicts 40 percent redemption is a belief the believer would disown on sight. The reference-prior analyst wants the data to speak; fine, but the flat prior's predictive, every count from 0 to n equally plausible, is what "letting the data speak" looks like before they do, and it is worth seeing. The weakly-informative analyst regularises toward plausible values and checks by prior prediction; this is the check. Nobody has to concede anything about where priors come from to run it, and the Wrong prior fails under all three positions.

LiveWhat Flat, Weak and Informed look like before the data2 min▶

The Flat prior, Beta(1, 1), treats every count from 0 to n as equally plausible. Its predictive is a level strip from zero redemptions to all of them. That is not a failure; it is a statement that the prior contributes two pseudo-observations and no opinion, and seeing the strip is how you confirm the prior you wrote is the prior you meant. Weak, Beta(2, 14), predicts a hill peaking inside the observed range with a long right tail that reaches well past it. Informed, Beta(12, 88), predicts a narrow hill entirely inside the range. Both pass the check in the only sense a prior predictive check has: they predict data that could be Halloway's.

Passing says nothing about whether the prior will be right for a given outlet. Session 2 already showed the Informed prior confidently wrong at Northgate, 0.110 with an interval of 0.068 to 0.159 against a truth of 0.192. It passed tonight's check anyway, because Northgate's truth of 0.192 is inside the range Halloway has seen and a prior centred at 0.120 predicts data like Halloway's. A prior predictive check catches a prior that predicts an impossible business. It does not catch a prior that predicts a plausible business and happens to be wrong about one shop. Hold onto that shape of sentence; Part 2 needs it again.

Self-studyWhat changed in the tool, and why the check is cheap now2 min▶

In PyMC 6, pm.sample_prior_predictive() is called bare inside the model block, before pm.sample(). Its deprecated samples argument was removed in 6.0.0, so a 2023 notebook that asked for a particular number of prior draws by that name stops at that line. The observed data are declared in the block so the model knows the shape of what it is predicting, 900 vouchers at Westfield, but the prior predictive does not condition on the 127. That is the whole point: the counts it returns are what the prior alone would produce.

Because it is one call and no sampler runs, there is no reason not to do it every time, and session 5's six-move walk already has it as move two. Leader session 6 tells a commissioning executive to ask whether a prior predictive simulation was run and reported as the range of counts the prior expects. Tonight is the session that produces the thing they are asking for.

Part 2 · covers the posterior predictive check and the wrong it cannot see

After the fit: could this model have produced these data?

6 min live

Now the model has been fitted and the question turns round. Simulate a fresh month from the posterior and lay it beside the month that happened. At Northgate the month that happened was one redemption in eighteen, 0.056. Complete pooling, which predicts every outlet at the grand rate of 0.141, expects more than that and treats one as a thin-tail event. Partial pooling, which shrinks Northgate toward 0.135 with its own month carrying weight 18 / (18 + 116), expects a little less and a little more spread, and the same count sits in a fatter tail. The figure draws the two predictive shapes with the observed count marked, and deliberately prints no tail probability, because that number is yours to compute in the build-along.

Northgate, one redemption in eighteen. What each fitted model expects to see in a fresh month of 18 vouchers. Complete pooling · every outlet at the grand rate 0.141 0 1 2 3 4 5 6 7 8 observed 1 of 18 redemptions predicted in 18 vouchers 1 of 18 sits in a thin left tail: surprising Partial pooling · Northgate shrunk to 0.124, data weight 0.13 0 1 2 3 4 5 6 7 8 observed 1 of 18 redemptions predicted in 18 vouchers 1 of 18 sits in a fatter left tail: less surprising Bar heights are the shapes the two models predict; no tail probability is printed. The build-along counts it, from your draws.
🔍 Click to zoom - the solid bar is the month that happened. On the left the model that gives every outlet the same rate did not expect it much. On the right the model that let Northgate be a little different expected it more. Neither picture says the model is right.
LiveNorthgate and Hillcrest under complete pooling, then under partial3 min▶

Complete pooling has one rate, the grand rate 0.141, and predicts every outlet's fresh month from it. Northgate's observed 1 of 18, 0.056, sits below that; Hillcrest's observed 9 of 40, 0.225, sits well above it. Under a single shared rate both months look like surprises, in opposite directions, and a posterior predictive check on complete pooling shows two outlets the model would not readily have produced. That is the check doing its job: the model's picture of the data is too tidy, and the twelve outlets are not all copies of 0.141.

Partial pooling, session 6's fit with mu = 0.135 and kappa = 116, predicts each outlet from its own shrunk rate. Northgate's is 0.124, its own month weighted at 18 / (18 + 116), so the fresh months it expects are lower and wider than complete pooling's, and one in eighteen sits in a fatter tail. Hillcrest, at n = 40, gets a data weight of 40 / (40 + 116), larger than Northgate's 0.13, so its predictive is allowed further from the centre toward its 0.225 and nine of forty is less of a surprise there too. The check cannot say partial pooling is right. It can say complete pooling has missed a shape in the data and partial pooling has not, and that is the kind of sentence McElreath's lecture 7 builds the check to produce. az.plot_ppc_dist(dt) draws exactly this comparison for any model in the tree.

LiveWhat a check cannot catch: wrong in the way the data agree with3 min▶

Session 6's partial pooling passed every check. Its diagnostics were clean, its predictive months at every outlet looked like the months on the table, and its ledger against the truth was the best of the three estimators, 0.025 root-mean-square error. It still put Northgate at 0.124 against a true rate of 0.192, and no predictive check could have told you so. Northgate's one redemption in eighteen is what a true 0.192 looks like at that size, so a model that predicts fresh months centred near 0.124 produces months that look like the observed one. The observed data confirm the model. The model is wrong about the one shop that mattered.

This is the sentence to carry out of tonight, and it is the honest limit of the whole idea. A predictive check compares the model to the data you have, and the data you have were small. It catches a model that could not have produced these data: the Wrong prior at Westfield, complete pooling at Northgate and Hillcrest. It cannot catch a model that produces these data comfortably and is wrong anyway, because the only evidence against it is a truth the data are too few to show. The same goes for the diagnostics, in the other direction: a passing R-hat and ESS set proves the sampler explored this model's posterior, and nothing about whether the model is right, which is exactly what tonight's checks are for. Two layers, two limits, and neither one is the truth.

Real world

The regional director asked the analyst whether the Northgate estimate had been checked. It had, twice: the diagnostics and the posterior predictive both passed. She said so, then added the line that mattered: "passing means the model could have produced one redemption in eighteen. So could a shop redeeming at nineteen percent. Eighteen vouchers cannot tell those apart, and no check on eighteen vouchers will." The director moved the question from the model to the sample size, which is where it belonged.

Self-studyNamed, not taught: the road onward from here2 min▶

Three things tonight names and leaves. LOO cross-validation is the tool for comparing two or more models by their predictive accuracy on held-out points; when the question is "which of these models predicts better", that is the answer, and it is a subject of its own. Bayes factors and comparison by marginal likelihood are a different way of comparing models, and they are what Kruschke's ROPE rule in session 7 is explicitly not: that rule is estimation against a band of practical equivalence, not a ratio of model evidences. And McElreath's lectures 14 to 18 are the road onward from twelve Beta-Binomial outlets: Gaussian processes, measurement error, missing data, social networks. Each is the same machine, a model run forwards to produce data, pointed at a harder shape of data.

One thing tonight does not do at all. Whether the 89 percent intervals these models report are honest over many forecasts, measured against what happened, is a calibration question, and learn-decision-intelligence-with-phoebe sessions 02 and 04 own it. A posterior predictive check asks whether the model could have made this month's data. Calibration asks whether its stated probabilities come true at the stated rate across many months. They are different questions with different owners.

Part 3 · build-along

The two checks in PyMC 6, then the Northgate comparison in scipy

24 min build-along

Two blocks. The first is PyMC 6.3 syntax: a prior predictive under the Wrong prior for Westfield, which should produce counts of 900 nowhere near anything Halloway has seen, then the flat Westfield model from session 5 with a posterior predictive and az.plot_ppc_dist. The canon numbers are in the comments: 127 of 900 observed, flat posterior mean 0.142. The second block is the Northgate comparison by pure simulation in scipy, which prints two shares and no course number, because the tail probabilities are yours.

Write the Westfield model with the Wrong prior. pm.Beta("rate", alpha=40, beta=60), pm.Binomial("redeemed", n=900, p=rate, observed=127). The observed line tells the model the shape of the data; the prior predictive will not use its value.

Sample the prior predictive, bare. pm.sample_prior_predictive() with no arguments; the samples argument is gone in PyMC 6. Print the result and read the redeemed counts: roughly 40 percent of 900, against a chain whose highest observed rate is 0.225. The prior has failed and no data were used.

Fit the flat model and sample its posterior predictive. Session 5's block, pm.sample(), then pm.sample_posterior_predictive(dt). Check the summary says 0.142 before going further; if it does not, the model or the count is wrong, not the check.

Plot it. az.plot_ppc_dist(dt), the ArviZ 1.x name; plot_ppc is the old one. Simulated counts of 900 against the observed 127. It returns a PlotCollection, not axes.

Build Northgate's two posteriors in scipy. Complete pooling: one flat-prior Beta on the grand rate from the summed counts of all twelve outlets. Partial pooling: Northgate's rate under the learned Beta(mu kappa, (1 - mu) kappa) prior with mu 0.135 and kappa 116, updated by 1 of 18.

Simulate fresh months and count. For each rate draw, a Binomial month of 18. Count how often 1 or fewer redeem under each model. Read the two printed values. They are from your draws and they are not course numbers; the shape, which is larger, is the lesson.

★ Run it now (Python) - prior predictive under the Wrong prior, then posterior predictive for the flat model# Westfield: 127 redeemed of 900. PyMC 6.3.2, ArviZ 1.3.0, Python 3.12 or later. import pymc as pm import arviz as az # 1. Prior predictive under the Wrong prior. No data are used: the observed line only tells # the model the shape of the data it is predicting, 900 vouchers. with pm.Model() as wrong_prior: rate = pm.Beta("rate", alpha=40, beta=60) # the Wrong prior: mean 0.400, worth 100 pseudo-observations pm.Binomial("redeemed", n=900, p=rate, observed=127) prior = pm.sample_prior_predictive() # PyMC 6: the deprecated samples argument is gone print(prior) # read the redeemed counts in the prior predictive group: # roughly 40 percent of 900, and Halloway has never seen # above 0.225 at any outlet (Hillcrest, 9 of 40). # The prior fails here, before the fit. # 2. Posterior predictive for the flat model, session 5's Westfield block. with pm.Model() as westfield: rate = pm.Beta("rate", alpha=1, beta=1) # flat, worth 2 pseudo-observations pm.Binomial("redeemed", n=900, p=rate, observed=127) dt = pm.sample() # nutpie when installed, 400 tuning steps dt = pm.sample_posterior_predictive(dt) # PyMC 6 added sample_vars and freeze_vars; extends dt and returns it print(az.rhat(dt)) # session 4's checks first: the sampler explored THIS posterior print(az.ess(dt, sample_dims=["chain", "draw"])) print(az.summary(dt)) # rate: mean 0.142, interval 89 percent equal-tailed by default pc = az.plot_ppc_dist(dt) # replaces plot_ppc; simulated counts of 900 against the observed 127 # returns a PlotCollection, like every ArviZ 1.x plot
★ Then the Northgate comparison - pure simulation in scipy, no PyMC# Northgate: 1 redeemed of 18. Two fitted models, two predictive distributions, one observed count. import numpy as np from scipy.stats import beta rng = np.random.default_rng(11) DRAWS = 20_000 n_out = np.array([18, 24, 31, 40, 55, 70, 95, 140, 210, 320, 540, 900]) # the twelve outlets y_out = np.array([1, 4, 1, 9, 8, 9, 7, 22, 19, 67, 71, 127]) # complete pooling: one rate for the whole chain, flat prior, conjugate posterior on the summed counts grand = beta(1 + y_out.sum(), 1 + n_out.sum() - y_out.sum()).rvs(DRAWS, random_state=rng) # centred on 0.141 # partial pooling: Northgate under the learned Beta(mu kappa, (1 - mu) kappa) prior, mu 0.135, kappa 116 mu, kappa = 0.135, 116 north = beta(mu * kappa + 1, (1 - mu) * kappa + 18 - 1).rvs(DRAWS, random_state=rng) # mean 0.124 # a fresh month of 18 vouchers from every rate draw, then: how often does 1 or fewer redeem? fresh_complete = rng.binomial(18, grand) fresh_partial = rng.binomial(18, north) print("complete pooling, share of fresh months with 1 or fewer redemptions:", np.mean(fresh_complete <= 1)) print("partial pooling, share of fresh months with 1 or fewer redemptions:", np.mean(fresh_partial <= 1)) # Read the two printed values. Neither is a course number; both are yours, from your draws. # The shape is the lesson: the second is larger, because Northgate's partially pooled rate sits # lower and wider than the grand rate. Less surprising is not the same as right: the truth is 0.192.

Run the prior predictive before you have an opinion about the fit. Once the posterior is on the screen it is very hard to look at Beta(40, 60) and see anything but the answer it produced, 0.167 at Westfield against a truth of 0.150. Before the fit it is easy: the prior predicts a business that has never existed. The check costs one line and it is the one line leader session 6 tells an executive to ask for.

Check yourself

Three questions

The Wrong prior Beta(40, 60) fails a prior predictive check at Westfield. What was compared to what?

A prior predictive check simulates from the prior alone. It never conditions on the observed count and never sees the truth. The Wrong prior fails because it predicts a business that has never existed at any outlet: the highest observed rate in the twelve-outlet table is Hillcrest's 9 of 40. That is why all three positions in leader session 5's argument can run it.

Session 6's partial pooling passed its diagnostics and its posterior predictive check, and estimated Northgate at 0.124 against a truth of 0.192. Which sentence is right?

A predictive check compares the model to the data you have, and the data you have were small. It catches a model that could not have produced these data, such as complete pooling at Northgate and Hillcrest. It cannot catch a model that produces them comfortably and is wrong anyway. Diagnostics are a different layer altogether: they prove the sampler explored this model's posterior, and nothing about the model.

Under complete pooling, Northgate's 1 of 18 and Hillcrest's 9 of 40 both look surprising in a posterior predictive check. Why does the same check make them look less surprising under partial pooling?

The pooling ladder gives each outlet a data weight n / (n + 116), so the shrunk rate sits between the centre 0.135 and the observed rate, and the predictive for a fresh month sits there too. Northgate is 0.124 under that rule, not 0.056, so option A is wrong; and the fit never sees the truth, so option C is wrong. Less surprising is not the same as right: Northgate's truth is still 0.192.

Homework

Before session 9

45 min

Take the model you brought from session 5 and run both checks on it. First the prior predictive: print the counts the prior alone produces and write one sentence saying whether they describe a business you have ever seen; if you have a Wrong prior in your notebook, this is where it dies. Then the posterior predictive with az.plot_ppc_dist, and one more sentence saying what shape in your data, if any, the model has missed. Finally write the sentence that tonight is really about, in your own units: "passing means the model could have produced these data; so could a model that is wrong by this much, and n of this size cannot tell them apart". Session 9 is the room where the number is read aloud, and that sentence is the one that has to survive the reading.

Sources covered

What tonight maps to

✓ Statistical Rethinking, lecture 7 "Overfitting", from the 2024 course: the source for predictive checks, run here forwards from the prior and forwards from the posterior on the Halloway models.
✓ The prior predictive check pm.sample_prior_predictive() in PyMC 6, the deprecated samples argument gone. The Wrong prior Beta(40, 60) predicts roughly 40 percent redemption against a highest observed rate of 0.225 (Hillcrest, 9 of 40) and fails before any data are used. Under Beta(1, 1) every count from 0 to n is equally plausible. The shared ground of leader session 5's prior argument.
✓ The posterior predictive check pm.sample_posterior_predictive(dt), which gained sample_vars and freeze_vars in PyMC 6; az.plot_ppc_dist replaces plot_ppc and returns a PlotCollection. Westfield flat model: 127 of 900 observed, posterior mean 0.142. Complete pooling predicts every outlet at 0.141, so Northgate's 1 of 18 and Hillcrest's 9 of 40 look surprising; under partial pooling, mu 0.135 and kappa 116 with data weight n / (n + 116), less so.
✓ What a check cannot catch A model wrong in a way the data confirm. Session 6's partial pooling passed every check and still put Northgate at 0.124 against a truth of 0.192, because one redemption in eighteen is what 0.192 looks like at that size. A check compares to the data you have, and the data you have were small.
✓ Diagnostics, in one clause A passing R-hat and ESS set proves the sampler explored this model's posterior and nothing about whether the model is right. Session 4 owns the diagnostics; tonight owns the other question.
◐ LOO cross-validation Named as the tool for comparing models by predictive accuracy on held-out points. Not taught.
◐ McElreath lectures 14 to 18 Gaussian processes, measurement error, missing data, social networks. Named as the road onward; not taught.
· Bayes factors and marginal-likelihood comparison Not covered by design. Named once as what Kruschke's ROPE rule in session 7 is explicitly not.
· Calibration over many forecasts Not covered by design. Whether the stated 89 percent comes true at that rate across many months is learn-decision-intelligence-with-phoebe sessions 02 and 04. A predictive check asks a different question about one month's data.

Session 8 cheat sheet

Prior predictivepm.sample_prior_predictive(), bare; no samples argument in PyMC 6. Simulate from the prior alone, ask if it could be real data.
The Wrong prior fails hereBeta(40, 60) predicts roughly 40 percent. Highest ever observed: Hillcrest 9 of 40, 0.225. Failed before any data.
Flat: every count equally plausibleBeta(1, 1) predicts 0 to n as a level strip. Two pseudo-observations and no opinion. Seeing it confirms the prior you meant.
Posterior predictivepm.sample_posterior_predictive(dt); gained sample_vars and freeze_vars. az.plot_ppc_dist(dt) replaces plot_ppc, returns a PlotCollection.
Complete vs partial at NorthgateComplete predicts 0.141 everywhere; 1 of 18 and Hillcrest's 9 of 40 look surprising. Partial shrinks with weight n / (n + 116); less so.
What a check cannot catchWrong in the way the data confirm. Northgate 0.124 vs 0.192: 1 of 18 is what 0.192 looks like at that size. Small data, small check.
Diagnostics are not thisR-hat and ESS prove the sampler explored THIS posterior. Nothing about whether the model is right. That is the predictive check's job.
Named, not taughtLOO for comparing models by predictive accuracy. Bayes factors: what the ROPE rule is not. McElreath 14 to 18: the road onward.