3. BBN Generation
BBN generation is available. We support singly- and multi-connected BBNs.
3.1. Singly-connected BBN
Use generate_singly_bbn() to generate a singly-connected BBN and then use create_reasoning_model() to create a reasoning model.
This example uses max_iter=20 so the generated tree is more illustrative than the initial ordered tree.
[1]:
from pybbn.factory import create_reasoning_model
from pybbn.generator import generate_singly_bbn
import numpy as np
g, p = generate_singly_bbn(
n=10, max_iter=20, max_values=2, max_alpha=10, rng=np.random.default_rng(seed=37)
)
model = create_reasoning_model(g, p)
The singly-connected BBN graph looks like the following.
[2]:
from help.viz import get_graph_layout
import networkx as nx
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(5, 5))
pos = get_graph_layout(g, seed=37)
nx.draw(g, pos=pos, with_labels=True, node_color="#e0e0e0")
fig.tight_layout()
Posterior queries proceed as usual.
[3]:
import pandas as pd
q1 = model.pquery(easy=True)
observed = list(model.d.nodes())[4]
states = model.domains[observed]
e = {observed: model.create_observation_evidences(observed, states[0])}
q2 = model.pquery(easy=True, evidences=e)
e = {observed: model.create_observation_evidences(observed, states[1])}
q3 = model.pquery(easy=True, evidences=e)
p1 = pd.Series({n: q1[n].iloc[0]["__p__"] for n in model.d.nodes()})
p2 = pd.Series({n: q2[n].iloc[0]["__p__"] for n in model.d.nodes()})
p3 = pd.Series({n: q3[n].iloc[0]["__p__"] for n in model.d.nodes()})
pd.DataFrame([p1, p2, p3]).T.rename(columns={0: "q1", 1: "q2", 2: "q3"})
[3]:
| q1 | q2 | q3 | |
|---|---|---|---|
| X0 | 0.122739 | 0.018840 | 0.269416 |
| X1 | 0.115061 | 0.032858 | 0.231107 |
| X2 | 0.627763 | 0.627688 | 0.627870 |
| X3 | 0.210991 | 0.210991 | 0.210991 |
| X4 | 0.585357 | 1.000000 | 0.000000 |
| X5 | 0.699483 | 0.876250 | 0.449937 |
| X6 | 0.612394 | 0.617927 | 0.604582 |
| X7 | 0.505644 | 0.507679 | 0.502771 |
| X8 | 0.394267 | 0.392686 | 0.396498 |
| X9 | 0.684198 | 0.684198 | 0.684198 |
[4]:
from pathlib import Path
from pybbn.serde import model_to_dict
import json
import tempfile
output_dir = Path(tempfile.gettempdir()) / "pybbn-docs"
output_dir.mkdir(exist_ok=True)
with (output_dir / "singly-connected.json").open("w") as fp:
json.dump(model_to_dict(model), fp, indent=1)
3.2. Multi-connected BBN
Use generate_multi_bbn() to generate a multi-connected BBN and then use create_reasoning_model() to create a reasoning model.
This example also uses max_iter=20 so the generated DAG moves farther from the initial ordered tree and better shows the additional connectivity.
[5]:
from pybbn.generator import generate_multi_bbn
g, p = generate_multi_bbn(
n=10, max_iter=20, max_values=2, max_alpha=10, rng=np.random.default_rng(seed=37)
)
model = create_reasoning_model(g, p)
[6]:
from help.viz import get_graph_layout
fig, ax = plt.subplots(figsize=(5, 5))
pos = get_graph_layout(g, seed=37)
nx.draw(g, pos=pos, with_labels=True, node_color="#e0e0e0")
fig.tight_layout()
[7]:
import pandas as pd
q1 = model.pquery(easy=True)
observed = list(model.d.nodes())[0]
states = model.domains[observed]
e = {observed: model.create_observation_evidences(observed, states[0])}
q2 = model.pquery(easy=True, evidences=e)
e = {observed: model.create_observation_evidences(observed, states[1])}
q3 = model.pquery(easy=True, evidences=e)
p1 = pd.Series({n: q1[n].iloc[0]["__p__"] for n in model.d.nodes()})
p2 = pd.Series({n: q2[n].iloc[0]["__p__"] for n in model.d.nodes()})
p3 = pd.Series({n: q3[n].iloc[0]["__p__"] for n in model.d.nodes()})
pd.DataFrame([p1, p2, p3]).T.rename(columns={0: "q1", 1: "q2", 2: "q3"})
[7]:
| q1 | q2 | q3 | |
|---|---|---|---|
| X0 | 0.690304 | 1.000000 | 0.000000 |
| X1 | 0.709774 | 0.686770 | 0.761050 |
| X2 | 0.254686 | 0.246655 | 0.272586 |
| X3 | 0.191932 | 0.156421 | 0.271086 |
| X4 | 0.544433 | 0.545465 | 0.542131 |
| X5 | 0.315296 | 0.315987 | 0.313756 |
| X6 | 0.671777 | 0.664806 | 0.687315 |
| X7 | 0.496768 | 0.498473 | 0.492967 |
| X8 | 0.367806 | 0.367324 | 0.368879 |
| X9 | 0.498058 | 0.499395 | 0.495079 |
[8]:
with (output_dir / "multi-connected.json").open("w") as fp:
json.dump(model_to_dict(model), fp, indent=1)