Also, in your case it is perfectly possible to have everything end to end in PyMC, the trick is to pad the “missing” greeting:
weather_prob = np.asarray([.2, .8]) # Sunny, Not sunny
greeting_prob = np.asarray([[.6, .4, 0.], # <= notice how the missing greeting has 0 probability
[.2, 0., .8]])
with pm.Model() as m:
observed = pm.Data('observed', 0, mutable=True)
weather = pm.Categorical('weather', weather_prob)
greeting = pm.Categorical('greeting',
aesara.shared(greeting_prob)[weather],
observed=observed)
# Simulate today’s greeting based on the (prior) probability of seeing sunny weather
prior_sample = pm.sample_prior_predictive(1000)
# Infer today’s weather based on an observed greeting
traces = []
for obs in range(3):
with m:
observed.set_value(obs)
traces.append(pm.sample(initvals={'weather': max(0, obs-1)}))
You can see that the result is the same as indexing to the prior_predictive @jessegrabowski explained:
_, axes = plt.subplots(1, 2, figsize=(5, 5), sharey=True)
for i, trace in enumerate(traces):
x, y = np.unique(trace.posterior['weather'], return_counts=True)
axes[0].bar(x + (i-1) / 5, y/y.sum(), width=.2);
x_, y_ = np.unique(
prior_sample.prior['weather'].values[prior_sample.prior_predictive['greeting'].values == i],
return_counts=True)
axes[1].bar(x_ + (i-1) / 5, y_/y_.sum(), width=.2);
axes[0].legend([f'observed = {i}' for i in range(3)])
