from pathlib import Path
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import lapylace as lp
root = Path("../../ROS-Examples")
def coef_medians(fit):
return pd.Series(
[np.median(fit.alpha_draws()), *np.median(fit.beta_draws(), axis=0)],
index=["Intercept", *fit.columns],
)
def fit_glm(formula, data, family=None, seed=1, prior_scale=2.5, intercept_scale=5, aux_scale=10, **kwargs):
return lp.stan_glm(
formula,
data=data,
family=family or lp.gaussian(),
prior=lp.normal(0, prior_scale),
prior_intercept=lp.normal(0, intercept_scale),
prior_aux=lp.exponential(aux_scale),
chains=2,
parallel_chains=2,
iter_warmup=300,
iter_sampling=500,
seed=seed,
refresh=100,
**kwargs,
)Earnings: height and weight
Source: Earnings/height_and_weight.Rmd
This page fits the weight regressions with lapylace Gaussian models and uses posterior predictions for uncertainty bands.
Setup
earnings = pd.read_csv(root / "Earnings/data/earnings.csv").dropna(subset=["weight", "height", "male", "ethnicity"])
earnings["c_height"] = earnings["height"] - earnings["height"].mean()
earnings.head()| height | weight | male | earn | earnk | ethnicity | education | mother_education | father_education | walk | exercise | smokenow | tense | angry | age | c_height | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 74 | 210.0 | 1 | 50000.0 | 50.0 | White | 16.0 | 16.0 | 16.0 | 3 | 3 | 2.0 | 0.0 | 0.0 | 45 | 7.40749 |
| 1 | 66 | 125.0 | 0 | 60000.0 | 60.0 | White | 16.0 | 16.0 | 16.0 | 6 | 5 | 1.0 | 0.0 | 0.0 | 58 | -0.59251 |
| 2 | 64 | 126.0 | 0 | 30000.0 | 30.0 | White | 16.0 | 16.0 | 16.0 | 8 | 1 | 2.0 | 1.0 | 1.0 | 29 | -2.59251 |
| 3 | 65 | 200.0 | 0 | 25000.0 | 25.0 | White | 17.0 | 17.0 | NaN | 8 | 1 | 2.0 | 0.0 | 0.0 | 57 | -1.59251 |
| 4 | 63 | 110.0 | 0 | 50000.0 | 50.0 | Other | 16.0 | 16.0 | 16.0 | 5 | 6 | 2.0 | 0.0 | 0.0 | 91 | -3.59251 |
fit_1 = fit_glm("weight ~ height", earnings, seed=17401, prior_scale=10, intercept_scale=100, aux_scale=50)
fit_2 = fit_glm("weight ~ c_height + male", earnings, seed=17402, prior_scale=10, intercept_scale=100, aux_scale=50)
pd.concat({"height": coef_medians(fit_1), "height + male": coef_medians(fit_2)}, axis=1).round(2)
| height | height + male | |
|---|---|---|
| Intercept | -171.31 | 151.99 |
| height | 4.92 | NaN |
| c_height | NaN | 3.92 |
| male | NaN | 11.54 |
grid = pd.DataFrame({"height": np.linspace(earnings.height.min(), earnings.height.max(), 100)})
grid["c_height"] = grid["height"] - earnings["height"].mean()
grid["male"] = 0
pred = fit_2.posterior_epred(grid)
fig, ax = plt.subplots()
ax.scatter(earnings.height, earnings.weight, alpha=.25, s=12)
ax.plot(grid.height, pred.mean(axis=0), color="black")
ax.fill_between(grid.height, np.quantile(pred, .1, axis=0), np.quantile(pred, .9, axis=0), color="0.8")
ax.set_xlabel("Height")
ax.set_ylabel("Weight")Text(0, 0.5, 'Weight')
