I fixed it myself with a code rewrite, borrowing some from the docs of OrderedLogistic. The following samples just fine, though I did notice in my obsessive checking that univariate_ordered didn’t actually order the cutpoints, but multivariate_ordered did. The following intercept-only model seems to work fine.
c = {'K': range(d['y'].nunique() - 1),
'Kt': range(d['y'].nunique()),
'N': range(len(d))
}
with pm.Model(coords=c) as ordinal:
# Priors for cutpoints
cut = pm.Normal('cut',
mu=np.linspace(-3, 3, num=len(c['K'])),
sigma=1,
transform=pm.distributions.transforms.multivariate_ordered,
dims='K')
# Prior for intercept
β0 = pm.Normal('β0', mu=0, sigma=1)
# Linear predictor
η = pm.Deterministic('η', pm.invlogit(cut - (β0 * d['intercept'].to_numpy()[:, None])), dims=('N', 'K'))
# Get probabilities now via subtraction
pa = pt.concatenate(
[
pt.zeros_like(η[:, [0]]),
η,
pt.ones_like(η[:, [0]])
],
axis=1)
p = pm.Deterministic('p',
pa[..., 1:] - pa[..., :-1],
dims=('N', 'Kt'))
# Likelihood
pm.Categorical('y', p=p, observed=d['y'].to_numpy())
Ordinal regression is destined to be my nemesis.