Imports¶
Install packages¶
!sudo /bin/bash -c "(source /venv/bin/activate; pip install --quiet jupyterlab-vim)"
!jupyter labextension enableImport modules¶
%load_ext autoreload
%autoreload 2
import arviz as az
import pandas as pd
import pymc as pm
import numpy as np
import matplotlib.pyplot as pltWARNING (pytensor.tensor.blas): Using NumPy C-API based implementation for BLAS functions.
import msml610.tutorials.msml610_utils as ut
ut.config_notebook()# Setting notebook style
# Notebook signature
Python 3.12.3
Linux ec1347f4acf5 6.10.14-linuxkit #1 SMP Tue Apr 15 16:00:54 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux
numpy version=1.26.4
pymc version=5.18.2
matplotlib version=3.10.3
arviz version=0.21.0
preliz version=0.19.0
Posterior predictive check: Examples¶
dir_name = "./L07_data"
!ls $dir_name# Load some data it's mainly a linear relationship with some data.
dummy_data = np.loadtxt(dir_name + "/dummy.csv")
x = dummy_data[:, 0]
y = dummy_data[:, 1]
# Transform the data applying various powers and stacking the data, so that
# we have different rows with different predicted variables.
order = 2
x_p = np.vstack([x**i for i in range(1, order + 1)])
display(pd.DataFrame(x_p))
# Normalize all the data.
x_c = (x_p - x_p.mean(axis=1, keepdims=True)) / x_p.std(axis=1, keepdims=True)
y_c = (y - y.mean()) / y.std()
# Plot the 0-order data (i.e., the original one).
plt.scatter(x_c[0], y_c)
plt.xlabel("x")
plt.ylabel("y")
ut.save_plt("Lesson07.Comparing_models.data.png")Loading...
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
Cell In[5], line 21
18 plt.xlabel('x')
19 plt.ylabel('y');
---> 21 ut.save_plt("Lesson07.Comparing_models.data.png")
File /app/msml610/tutorials/msml610_utils.py:757, in save_plt(file_name)
755 def save_plt(file_name):
756 file_name = os.path.join(fig_dir, file_name)
--> 757 plt.savefig(file_name, dpi=300, bbox_inches="tight")
758 #
759 file_name = file_name.replace("/app/", "")
File /venv/lib/python3.12/site-packages/matplotlib/pyplot.py:1251, in savefig(*args, **kwargs)
1248 fig = gcf()
1249 # savefig default implementation has no return, so mypy is unhappy
1250 # presumably this is here because subclasses can return?
-> 1251 res = fig.savefig(*args, **kwargs) # type: ignore[func-returns-value]
1252 fig.canvas.draw_idle() # Need this if 'transparent=True', to reset colors.
1253 return res
File /venv/lib/python3.12/site-packages/matplotlib/figure.py:3490, in Figure.savefig(self, fname, transparent, **kwargs)
3488 for ax in self.axes:
3489 _recursively_make_axes_transparent(stack, ax)
-> 3490 self.canvas.print_figure(fname, **kwargs)
File /venv/lib/python3.12/site-packages/matplotlib/backend_bases.py:2184, in FigureCanvasBase.print_figure(self, filename, dpi, facecolor, edgecolor, orientation, format, bbox_inches, pad_inches, bbox_extra_artists, backend, **kwargs)
2180 try:
2181 # _get_renderer may change the figure dpi (as vector formats
2182 # force the figure dpi to 72), so we need to set it again here.
2183 with cbook._setattr_cm(self.figure, dpi=dpi):
-> 2184 result = print_method(
2185 filename,
2186 facecolor=facecolor,
2187 edgecolor=edgecolor,
2188 orientation=orientation,
2189 bbox_inches_restore=_bbox_inches_restore,
2190 **kwargs)
2191 finally:
2192 if bbox_inches and restore_bbox:
File /venv/lib/python3.12/site-packages/matplotlib/backend_bases.py:2040, in FigureCanvasBase._switch_canvas_and_return_print_method.<locals>.<lambda>(*args, **kwargs)
2036 optional_kws = { # Passed by print_figure for other renderers.
2037 "dpi", "facecolor", "edgecolor", "orientation",
2038 "bbox_inches_restore"}
2039 skip = optional_kws - {*inspect.signature(meth).parameters}
-> 2040 print_method = functools.wraps(meth)(lambda *args, **kwargs: meth(
2041 *args, **{k: v for k, v in kwargs.items() if k not in skip}))
2042 else: # Let third-parties do as they see fit.
2043 print_method = meth
File /venv/lib/python3.12/site-packages/matplotlib/backends/backend_agg.py:481, in FigureCanvasAgg.print_png(self, filename_or_obj, metadata, pil_kwargs)
434 def print_png(self, filename_or_obj, *, metadata=None, pil_kwargs=None):
435 """
436 Write the figure to a PNG file.
437
(...)
479 *metadata*, including the default 'Software' key.
480 """
--> 481 self._print_pil(filename_or_obj, "png", pil_kwargs, metadata)
File /venv/lib/python3.12/site-packages/matplotlib/backends/backend_agg.py:430, in FigureCanvasAgg._print_pil(self, filename_or_obj, fmt, pil_kwargs, metadata)
425 """
426 Draw the canvas, then save it using `.image.imsave` (to which
427 *pil_kwargs* and *metadata* are forwarded).
428 """
429 FigureCanvasAgg.draw(self)
--> 430 mpl.image.imsave(
431 filename_or_obj, self.buffer_rgba(), format=fmt, origin="upper",
432 dpi=self.figure.dpi, metadata=metadata, pil_kwargs=pil_kwargs)
File /venv/lib/python3.12/site-packages/matplotlib/image.py:1657, in imsave(fname, arr, vmin, vmax, cmap, format, origin, dpi, metadata, pil_kwargs)
1655 pil_kwargs.setdefault("format", format)
1656 pil_kwargs.setdefault("dpi", (dpi, dpi))
-> 1657 image.save(fname, **pil_kwargs)
File /venv/lib/python3.12/site-packages/PIL/Image.py:2576, in Image.save(self, fp, format, **params)
2574 fp = builtins.open(filename, "r+b")
2575 else:
-> 2576 fp = builtins.open(filename, "w+b")
2577 else:
2578 fp = cast(IO[bytes], fp)
FileNotFoundError: [Errno 2] No such file or directory: '/app/lectures_source/figures/Lesson07.Comparing_models.data.png'
# Linear model.
with pm.Model() as model_l:
# mu = alpha + beta * x
alpha = pm.Normal("alpha", mu=0, sigma=1)
beta = pm.Normal("beta", mu=0, sigma=10)
mu = alpha + beta * x_c[0]
#
sigma = pm.HalfNormal("sigma", 5)
#
y_pred = pm.Normal("y_pred", mu=mu, sigma=sigma, observed=y_c)
#
idata_l = pm.sample(2000, idata_kwargs={"log_likelihood": True})
idata_l.extend(pm.sample_posterior_predictive(idata_l))
# Quadratic model.
with pm.Model() as model_p:
# mu = alpha + beta_1 * x + beta_2 * x^2
alpha = pm.Normal("alpha", mu=0, sigma=1)
# Beta is a 2-dim vector.
beta = pm.Normal("beta", mu=0, sigma=10, shape=order)
mu = alpha + pm.math.dot(beta, x_c)
#
sigma = pm.HalfNormal("sigma", 5)
#
y_pred = pm.Normal("y_pred", mu=mu, sigma=sigma, observed=y_c)
#
idata_q = pm.sample(2000, idata_kwargs={"log_likelihood": True})
idata_q.extend(pm.sample_posterior_predictive(idata_q))#
# Plot the data and the fit linear and quadratic models (using the mean posterior).
#
# Sample the x space uniformly with 100 samples.
x_new = np.linspace(x_c[0].min(), x_c[0].max(), 100)
# Posterior.
posterior_l = az.extract(idata_l)
posterior_p = az.extract(idata_q)
# print(posterior_l)
# Compute the mean posterior of the linear model.
alpha_l_post = posterior_l["alpha"].mean().item()
beta_l_post = posterior_l["beta"].mean().item()
print(
f"linear model: alpha_l_post={alpha_l_post:.2g}, beta_l_post={beta_l_post:.2g}"
)
y_l_post = alpha_l_post + beta_l_post * x_new
# Plot the mean posterior of the linear model.
plt.plot(x_new, y_l_post, "C0", label="linear model")
# Quadratic model.
alpha_p_post = posterior_p["alpha"].mean().item()
beta_p_post = posterior_p["beta"].mean("sample")
print(
f"quadratic model: alpha_p_post={alpha_p_post:.2g}, beta_post[0]={beta_p_post[0]:.2g}, beta_post[1]={beta_p_post[1]:.2g}"
)
y_p_post = alpha_p_post + np.dot(beta_p_post, x_c)
# idx = np.argsort(x_c[0])
# plt.plot(x_c[0][idx], y_p_post[idx], "C1", label="quadratic model")
plt.plot(x_c[0], y_p_post, "C1", label="quadratic model")
# Plot data.
plt.plot(x_c[0], y_c, "C2.")
ut.save_plt("Lesson07.Comparing_models.model_fit.png")#
# Plot the posterior predictive check for both models.
#
az.plot_ppc(idata_l, num_pp_samples=100, colors=["C1", "C0", "C1"])
plt.title("linear model")
ut.save_plt("Lesson07.Comparing_models.lin_model_PPC.png")
az.plot_ppc(idata_q, num_pp_samples=100, colors=["C1", "C0", "C1"])
plt.title("quadratic model")
ut.save_plt("Lesson07.Comparing_models.quadr_model_PPC.png")# ?az.plot_bpvBayesian p-value¶
#
# Compare the Bayesian p-value for a statistic for linear and quadratic model.
#
colors = ["C0", "C1"]
idatas = [idata_l, idata_q]
fig, axes = plt.subplots(2, 1)
# Plot the Bayesian p-value for mean for both models.
for idata, c in zip(idatas, colors):
# Plot Bayesian p-value.
az.plot_bpv(idata, kind="t_stat", t_stat="mean", ax=axes[0], color=c)
axes[0].set_title("linear")
# Plot the Bayesian p-value for interquartile range for both models.
def iqr(x, a=-1):
"""
Interquartile range.
"""
return np.subtract(*np.percentile(x, [75, 25], axis=a))
for idata, c in zip(idatas, colors):
# Plot Bayesian p-value.
az.plot_bpv(idata, kind="t_stat", t_stat=iqr, ax=axes[1], color=c)#
# Compare Bayesian p-value for entire distribution.
#
fig, ax = plt.subplots()
for idata, c in zip(idatas, colors):
az.plot_bpv(idata, color=c, ax=ax)Overfitting¶
_, ax = plt.subplots(1, 1)
x0 = np.array([4.0, 5.0, 6.0, 9.0, 12, 14.0])
y0 = np.array([4.2, 6.1, 5.0, 10.0, 10, 14.0])
x1 = np.array([6.5, 10])
y1 = np.array([7, 10])
ax.plot(x0, y0, "ko")
ax.plot(x1, y1, "rs")#
# Fit model on in-sample data.
#
_, ax = plt.subplots(1, 1)
# Data.
x0 = np.array([4.0, 5.0, 6.0, 9.0, 12, 14.0])
y0 = np.array([4.2, 6.1, 5.0, 10.0, 10, 14.0])
ax.plot(x0, y0, "ko", zorder=3)
# Learn 3 models.
order = [0, 1, 5]
x_n = np.linspace(x0.min(), x0.max(), 100)
ps = []
for i in order:
# Learn the models.
p = np.polynomial.Polynomial.fit(x0, y0, deg=i)
ps.append(p)
#
def plot_models(x0, y0, ps):
for i in range(len(order)):
p = ps[i]
# Evaluate on the raw data.
yhat = p(x0)
# Estimate the error between the estimates and the true values.
ss_regression = np.sum((yhat - y0) ** 2)
# Compute R^2.
ybar = np.mean(y0)
ss_total = np.sum((ybar - y0) ** 2)
r2 = 1 - ss_regression / ss_total
#
ax.plot(x_n, p(x_n), label=f"order {i}, $R^2$= {r2:.3f}", lw=3)
ax.legend(loc=2)
plot_models(x0, y0, ps)#
# Evaluate the fit model on the out-of-sample data.
#
_, ax = plt.subplots(figsize=(12, 4))
x_ = np.array([6.5, 10])
y_ = np.array([7, 10])
ax.plot(x0, y0, "ko", zorder=3)
ax.plot(x_, y_, "rs", zorder=3)
x1 = np.concatenate((x0, x_))
y1 = np.concatenate((y0, y_))
plot_models(x1, y1, ps)Calculating predictive accuracy¶
waic_l = az.waic(idata_l)
waic_lwaic_q = az.waic(idata_q)
waic_qloo_l = az.loo(idata_l)
loo_lloo_q = az.loo(idata_q)
loo_qComparing models¶
cmp_df = az.compare({"model_l": idata_l, "model_q": idata_q})
display(cmp_df)az.plot_compare(cmp_df)Model averaging¶
idatas = [idata_l, idata_q]
weights = [0.35, 0.65]
idata_w = az.weight_predictions(idatas, weights)# Plot the KDE of the posterior predictive.
_, ax = plt.subplots(figsize=(10, 6))
# Linear.
az.plot_kde(
idata_l.posterior_predictive["y_pred"].values,
plot_kwargs={"color": "C0", "lw": 3},
label="linear",
ax=ax,
)
# Quadratic.
az.plot_kde(
idata_q.posterior_predictive["y_pred"].values,
plot_kwargs={"color": "C1", "lw": 3},
label="quadratic",
ax=ax,
)
# Weighted.
az.plot_kde(
idata_w.posterior_predictive["y_pred"].values,
plot_kwargs={"color": "C2", "lw": 3, "ls": "--"},
label="weighted",
ax=ax,
)
plt.legend()