Probabilistic programming turns a generative process into executable code by combining ordinary program logic with random-variable sampling. Instead of requiring one canonical joint distribution, it factorizes dependencies and samples variables in sequence: first Z, then X conditioned on Z, then Y conditioned on X. Conditional independence assumptions determine which simpler distributions can be composed. section 2.2.3
The implementation pattern is:
- Represent each variable with a distribution and encode dependencies through conditioning. section 2.2.3
- Use library-supported distributions or combine canonical distributions when the model requires more flexible parameterization. section 2.2.3
- Add ordinary control flow such as loops, allowing the number or structure of random variables to depend on sampled values. section 2.2.3
- Name random choices with pyro.sample so the program exposes a model that can be rendered, simulated, or intervened on. section 2.2.3 section 7.1.6
Simulating an intervention on game engagement
A Pyro model samples Guild Membership, samples Side-Quest Engagement conditional on membership, and samples In-Game Purchases from parameters for each combination of those variables. Applying pyro.do fixes engagement to high or low, then generates 500 observations for each intervention. The resulting group means provide simulated experimental summaries that can be compared with actual experimental summaries. section 7.1.6
Listing 2.5 Creating a random process in pgmpy and Pyro
from pgmpy.factors.discrete.CPD import TabularCPD
from pgmpy.models import BayesianNetwork
from pgmpy.sampling import BayesianModelSampling
PZ = TabularCPD( #1
variable='Z', #1
variable_card=2, #1
values=[[.65], [.35]], #1
state_names = { #1
'Z': ['0', '1'] #1
}) #1
PXgivenZ = TabularCPD( #2
variable='X', #2
variable_card=2, #2
values=[ #2
[.8, .6], #2
[.2, .4], #2
], #2
evidence=['Z'], #2
evidence_card=[2], #2
state_names = { #2
'X': ['0', '1'], #2
'Z': ['0', '1'] #2
}) #2
PYgivenX = TabularCPD( #3
variable='Y', #3
variable_card=3, #3
values=[ #3
[.1, .8], #3
[.2, .1], #3
[.7, .1], #3
], #3
evidence=['X'], #3
evidence_card=[2], #3
state_names = { #3
'Y': ['1', '2', '3'], #3
'X': ['0', '1'] #3
}) #3
model = BayesianNetwork([('Z', 'X'), ('X', 'Y')]) #4
model.add_cpds(PZ, PXgivenZ, PYgivenX) #5
generator = BayesianModelSampling(model) #6
generator.forward_sample(size=1) #7
Inspect the paired pgmpy and Pyro implementation for a random process over Z, X, and Y. section 2.2.3
