import pymc as pm
import numpy as np
import arviz as az
from pytensor.tensor import subtensor as st
%load_ext lab_black
%load_ext watermark
17. Multinomial regression*#
Adapted from Unit 7: NHANESmulti.odc
Problem statement#
The National Health and Nutrition Examination Survey (NHANES) is a program of studies designed to assess the health and nutritional status of adults and children in the United States. The survey is unique in that it combines interviews and physical examinations.
Assume that N subjects select a choice form K categories. The i-th subject is characterized by 3 covariates x[i,1], x[i,2], and x[i,3]. Given the covariates, model the probability of a subject selecting the category k, k=1,…,K.
# data
# fmt: off
y = np.array([[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1],
[0, 0, 0, 0, 1],
[0, 0, 0, 1, 0]])
X =np.array([[2, 4, 9],
[1, 5, 10],
[1, 6, 14],
[2, 4, 21],
[2, 4, 22],
[2, 6, 30],
[3, 3, 33],
[3, 2, 36],
[3, 1, 40],
[4, 1, 44]])
# fmt: on
y.shape
(10, 5)
X_aug = np.concatenate((np.ones((X.shape[0], 1)), X), axis=1)
X_aug.shape
(10, 4)
with pm.Model() as m:
y_data = pm.Data("y", y, mutable=False)
X_data = pm.Data("X", X_aug, mutable=True)
_beta = pm.Normal("_beta", 0, tau=0.1, shape=(4, 5))
# first col in BUGS example is assigned 0
# might be better to prepend a column of zeroes rather than overwrite
beta = pm.Deterministic("beta", st.set_subtensor(_beta[:, 0], 0))
eta = pm.math.exp(pm.math.dot(X_data, beta))
p = eta / pm.math.sum(eta, axis=1)
pm.Multinomial("likelihood", n=1, p=p, observed=y)
trace = pm.sample(10000)
/Users/aaron/mambaforge/envs/pymc_env2/lib/python3.11/site-packages/multipledispatch/dispatcher.py:27: AmbiguityWarning:
Ambiguities exist in dispatched function _unify
The following signatures may result in ambiguous behavior:
[object, ConstrainedVar, Mapping], [ConstrainedVar, object, Mapping]
[ConstrainedVar, object, Mapping], [object, ConstrainedVar, Mapping]
[ConstrainedVar, Var, Mapping], [object, ConstrainedVar, Mapping]
[object, ConstrainedVar, Mapping], [ConstrainedVar, Var, Mapping]
Consider making the following additions:
@dispatch(ConstrainedVar, ConstrainedVar, Mapping)
def _unify(...)
@dispatch(ConstrainedVar, ConstrainedVar, Mapping)
def _unify(...)
@dispatch(ConstrainedVar, ConstrainedVar, Mapping)
def _unify(...)
@dispatch(ConstrainedVar, ConstrainedVar, Mapping)
def _unify(...)
warn(warning_text(dispatcher.name, ambiguities), AmbiguityWarning)
Auto-assigning NUTS sampler...
Initializing NUTS using jitter+adapt_diag...
Multiprocess sampling (4 chains in 4 jobs)
NUTS: [_beta]
100.00% [44000/44000 01:18<00:00 Sampling 4 chains, 0 divergences]
Sampling 4 chains for 1_000 tune and 10_000 draw iterations (4_000 + 40_000 draws total) took 79 seconds.
X_new = np.array([1, 3, 3, 30]).reshape((1, 4))
with m:
pm.set_data({"X": X_new})
ppc = pm.sample_posterior_predictive(trace, predictions=True)
Sampling: [likelihood]
100.00% [40000/40000 00:05<00:00]
ppc
arviz.InferenceData
-
<xarray.Dataset> Dimensions: (chain: 4, draw: 10000, likelihood_dim_2: 10, likelihood_dim_3: 5) Coordinates: * chain (chain) int64 0 1 2 3 * draw (draw) int64 0 1 2 3 4 5 ... 9994 9995 9996 9997 9998 9999 * likelihood_dim_2 (likelihood_dim_2) int64 0 1 2 3 4 5 6 7 8 9 * likelihood_dim_3 (likelihood_dim_3) int64 0 1 2 3 4 Data variables: likelihood (chain, draw, likelihood_dim_2, likelihood_dim_3) int64 ... Attributes: created_at: 2023-02-03T08:12:53.521049 arviz_version: 0.14.0 inference_library: pymc inference_library_version: 5.0.1
-
<xarray.Dataset> Dimensions: (y_dim_0: 10, y_dim_1: 5, X_dim_0: 1, X_dim_1: 4) Coordinates: * y_dim_0 (y_dim_0) int64 0 1 2 3 4 5 6 7 8 9 * y_dim_1 (y_dim_1) int64 0 1 2 3 4 * X_dim_0 (X_dim_0) int64 0 * X_dim_1 (X_dim_1) int64 0 1 2 3 Data variables: y (y_dim_0, y_dim_1) int32 1 0 0 0 0 0 1 0 0 0 ... 0 0 0 1 0 0 0 1 0 X (X_dim_0, X_dim_1) float64 1.0 3.0 3.0 30.0 Attributes: created_at: 2023-02-03T08:12:53.522162 arviz_version: 0.14.0 inference_library: pymc inference_library_version: 5.0.1
az.summary(ppc.predictions.mean(dim=("likelihood_dim_2")))
mean | sd | hdi_3% | hdi_97% | mcse_mean | mcse_sd | ess_bulk | ess_tail | r_hat | |
---|---|---|---|---|---|---|---|---|---|
likelihood[0] | 0.008 | 0.050 | 0.0 | 0.0 | 0.000 | 0.000 | 35823.0 | 35822.0 | 1.0 |
likelihood[1] | 0.038 | 0.118 | 0.0 | 0.2 | 0.001 | 0.000 | 40230.0 | 38995.0 | 1.0 |
likelihood[2] | 0.118 | 0.208 | 0.0 | 0.6 | 0.001 | 0.001 | 40260.0 | 37228.0 | 1.0 |
likelihood[3] | 0.683 | 0.310 | 0.1 | 1.0 | 0.002 | 0.001 | 40808.0 | 37358.0 | 1.0 |
likelihood[4] | 0.153 | 0.228 | 0.0 | 0.6 | 0.001 | 0.001 | 43723.0 | 38330.0 | 1.0 |
az.summary(ppc.predictions.mean(dim=("likelihood_dim_2")))["mean"].sum()
1.0
%watermark -n -u -v -iv -p aesara,aeppl
Last updated: Fri Feb 03 2023
Python implementation: CPython
Python version : 3.11.0
IPython version : 8.9.0
aesara: 2.8.10
aeppl : 0.1.1
pymc : 5.0.1
arviz : 0.14.0
pytensor: 2.8.11
numpy : 1.24.1